楼主: abrahamSu

[原创] 为什么ORACLE加上索引后JOIN操作变的更慢???

[复制链接]
论坛徽章:
60
2007年度最佳版主
日期:2008-04-03 16:46:15现任管理团队成员
日期:2011-05-07 01:45:08双黄蛋
日期:2011-06-15 17:03:34ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20
11#
发表于 2005-1-25 15:32 | 只看该作者

Re: to "Fenng Che Guevara".

最初由 abrahamSu 发布
[B]你的意思我理解,但是你应该知道JOIN的实现方法吧,所以你回答的没到点上啊.对吗? [/B]


你没问到点子上

你的执行计划呢?

使用道具 举报

回复
论坛徽章:
60
2007年度最佳版主
日期:2008-04-03 16:46:15现任管理团队成员
日期:2011-05-07 01:45:08双黄蛋
日期:2011-06-15 17:03:34ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20
12#
发表于 2005-1-25 15:36 | 只看该作者
出现了嵌套循环

想办法避免这个

使用道具 举报

回复
论坛徽章:
0
13#
 楼主| 发表于 2005-1-25 15:42 | 只看该作者
当有INDEX的时候PLAN:
SQL> select count(*) from test20m1,test20m2 where test20m1.empno=test20m2.empno;

  COUNT(*)
----------
   1420048


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   SORT (AGGREGATE)
   2    1     NESTED LOOPS
   3    2       TABLE ACCESS (FULL) OF 'TEST20M2'
   4    2       INDEX (RANGE SCAN) OF 'INDEXTEST20M1' (NON-UNIQUE)




Statistics
----------------------------------------------------------
          0  recursive calls
          4  db block gets
     422097  consistent gets
     167394  physical reads
          0  redo size
        583  bytes sent via SQL*Net to client
        938  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
          1  rows processed

当去掉INDEX的时候PLAN:
SQL> select count(*) from test20m1,test20m2 where test20m1.empno=test20m2.empno;

  COUNT(*)
----------
   1420048


Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   SORT (AGGREGATE)
   2    1     MERGE JOIN
   3    2       SORT (JOIN)
   4    3         TABLE ACCESS (FULL) OF 'TEST20M2'
   5    2       SORT (JOIN)
   6    5         TABLE ACCESS (FULL) OF 'TEST20M1'




Statistics
----------------------------------------------------------
       3157  recursive calls
      21190  db block gets
      18873  consistent gets
      26926  physical reads
      65128  redo size
        582  bytes sent via SQL*Net to client
        938  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          3  sorts (memory)
          2  sorts (disk)
          1  rows processed

SQL>

使用道具 举报

回复
论坛徽章:
0
14#
 楼主| 发表于 2005-1-25 15:52 | 只看该作者
想什么办法避免这个呢,老大?

使用道具 举报

回复
论坛徽章:
86
ITPUB元老
日期:2005-02-28 12:57:002012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20咸鸭蛋
日期:2012-05-08 10:27:19版主8段
日期:2012-05-15 15:24:112013年新春福章
日期:2013-02-25 14:51:24
15#
发表于 2005-1-25 16:42 | 只看该作者
什么版本数据库?
返回结果集大的话
分析表,希望走 hash  join

如果不行就使用 hints  (假定 test20m1 记录少于  test20m2)
select  /*+ordered  use_hash(test20m1   test20m2)*/ count(*) from test20m1,test20m2 where test20m1.empno=test20m2.empno;

使用道具 举报

回复
论坛徽章:
0
16#
 楼主| 发表于 2005-1-25 17:28 | 只看该作者
PL/SQL Release 8.0.5.0.0 - Production
其实,我只是想知道理由,加HINTS肯定是好的.(count(test20m1)=count(test20m2).=200,000.

使用道具 举报

回复
论坛徽章:
86
ITPUB元老
日期:2005-02-28 12:57:002012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20咸鸭蛋
日期:2012-05-08 10:27:19版主8段
日期:2012-05-15 15:24:112013年新春福章
日期:2013-02-25 14:51:24
17#
发表于 2005-1-25 17:35 | 只看该作者
你既然知道使用hints好----》  那就应该知道是执行计划问题-----》  为什么这个执行计划好?


很显然这里 nested  loops 不好啊

使用道具 举报

回复
论坛徽章:
0
18#
 楼主| 发表于 2005-1-25 18:19 | 只看该作者
这是动态SQL问题,具体是什么数据表,我提前是不知道的,只能让ORACLE 自己去优化;也就是说,SQL语句不是写死的,来什么表,几个表,表的关联字段是什么我根本不知道.明白了吧,大侠.
所以说这种HINTS根本没法用的.

使用道具 举报

回复
论坛徽章:
0
19#
 楼主| 发表于 2005-1-25 18:38 | 只看该作者

大侠,偶还是把代码给你,吧,这样你会很明白.

/*
    HERE,we get every column's values size and write value into file,
  just same size with defined.
    TO get it,we use L to get every size and use L[0]+..+L[END] as
  a buffer size,we write all column value into the buffer and then
  write buffer into file.
    TO do more is,we can malloc more buffer and write more big block into file
  to save time.
*/

#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include <sqlda.h>
#include <stdlib.h>
#include <sqlcpr.h>

     #include <time.h>
     #include <sys/timeb.h>
     #include <sys/types.h>
     
#define MAX_SELECT_ITEMS 30
#define MAX_NAME_SIZE  50
/*funcs
*/
int getNowTime(int *hour,int *min,int *sec,short *mill);
void printSqlda(SQLDA *sqlDa);
void sql_error();
int intValueSize(int intValue);
void printUseTime(int h1,int m1,int s1,int mi1,int h2,int m2,int s2,int mi2);
/*end funcs
*/

EXEC SQL INCLUDE sqlda;
EXEC SQL INCLUDE sqlca;

SQLDA   *selda;
char *username = "abc/abc@ora803abc";
char *stmt=0;
char fileName[20]="tempData.txt";


/*==========main==========*/
void main(int argc,char  *argv[]) {
      int sqlaldRet;
      int row_count;   
      int sli;
      int null_ok;
      int precision, scale;   
        
      int row2, sli2;/*use in write into file.*/
      char *fileHeader=0;
      int fileHeaderSize=0;
      int fileHeaderSizeSize1=0;
      int fileHeaderSizeSize2=0;
      char *fileHeaderP=0;
      char tempIntStr[10];
      char *buffer=0;  
      char *p=NULL;  
      FILE *fd;  
      int bufferSize=0;
      char *bufferP=0;
      
      int hour,min,sec;
      int hour2,min2,sec2;

      short mil;
      short mil2;
      
      stmt=(char*)malloc(100);
      printf("input table name:";
      fgets(stmt,100,stdin);
      printf("\n";
      printf("input file name:";
      /*
      fgets(fileName,20,stdin);
      */
      /*
      strcpy(stmt,argv[1]);
      */
      
      printf("you have input sql is:%s\n",stmt);
      
      printf("you have input file name:%s\n",fileName);
     
      fd=fopen(fileName,"w";
      
      if(fd==NULL){
      printf("can not open file tempResult1.txt!\n";
      return;
      }   
      EXEC SQL CONNECT :username;     
      if (sqlca.sqlcode == 0)        
        printf("Connected.\n";     
      else    {        
        printf("Cannot connect %s.\n",username);        
        exit(EXIT_FAILURE);   
      }   
      
      EXEC SQL WHENEVER SQLERROR DO sql_error();   
      sqlaldRet=selda = sqlald(MAX_SELECT_ITEMS, MAX_NAME_SIZE, 1);
      if(sqlaldRet<=0){
          printf("error when sqlald..\n";
          return;
      }
      EXEC SQL PREPARE S FROM :stmt;   
      EXEC SQL DECLARE C CURSOR FOR S;   
      EXEC SQL OPEN C;   
      EXEC SQL DESCRIBE SELECT LIST FOR S INTO selda;
      /*--now print info about selda--*/
/*
printf("--after describe select into sqlda--\n";
printSqlda(selda);  
*/
      selda->N = selda->F;   
      /*malloc size of mem for every value*/
      fileHeader=(char*)malloc(1000);
      fileHeaderP=fileHeader;
      fileHeaderP+=12;/*used to as [2333..] as headerSize*/
      
      for (sli = 0; sli < selda->N; sli++){
           /*after describe ,we can deal with every select item's name,S[sli] an C[sli],
             we just put them and write it as data file header.
           */
           
           strncpy(fileHeaderP,selda->S[sli],selda->C[sli]);
           fileHeaderP+=selda->C[sli];
           fileHeaderSize+=selda->C[sli];
           sprintf(fileHeaderP,"(%d)",selda->C[sli]);
           if(selda->C[sli]>10){
               fileHeaderP+=2+2;
           }else{
               if(selda->C[sli]<10&&selda->C[sli]>0){
                   fileHeaderP+=3;
               }else{
                   printf("ERROR,too big columnNameSize";
                   fileHeaderP+=0;
               }
           }
           
           
           
                  /*now , oracle have set value's length into L
                    but,we must reset length of V to make it can contain all
                    value from value of all type.
                    and we must reset L to use L malloc mem to store value.
                  */
                  /*reset internal type by oracle*/
                  sqlnul((unsigned short *)&(selda->T[sli]), (unsigned short *)&(selda->T[sli]), &null_ok);
                  
                  switch (selda->T[sli])
        {
            case  1 : /* CHAR datatype: no change in length
                         needed, except possibly for TO_CHAR
                         conversions (not handled here).
                      */
                break;
            case  2 : /* NUMBER datatype: use sqlprc() to
                         extract precision and scale.
                      */
                /*     
                sqlprc ((unsigned long *)&(selda->L[sli]), &precision, &scale);
                */
                      /* Allow for maximum size of NUMBER.
                      */
                 /*     
                if (precision == 0) precision = 40;
                */
                      /* Also allow for decimal point and
                         possible sign.
                      */
                /* convert NUMBER datatype to FLOAT if scale > 0,
                   INT otherwise.
                */
                /*
                if (scale > 0)
                    selda->L[sli] = sizeof(float);
                else
                    selda->L[sli] = sizeof(int);
                break;
                */
                /*we set it as 10*/
                selda->L[sli]=10;
                break;

            case  8 : /* LONG datatype */
               selda->L[sli] = 240;
                break;

            case 11 : /* ROWID datatype */
            case 104 : /* Universal ROWID datatype */
                selda->L[sli] = 18;
                break;

            case 12 : /* DATE datatype */
                selda->L[sli] = 9;
                break;

            case 23 : /* RAW datatype */
                break;

            case 24 : /* LONG RAW datatype */
                selda->L[sli] = 240;
                break;
        }
                  
        selda->V[sli] = (char *)malloc(selda->L[sli]);  
        printf("in txt size:%d\n",selda->L[sli]);
        /* here we add malloc I[sil] to make the can set I to indicate
           whether the current row's column is NULL(-1),then can deal.
        */
        selda->I[sli]=(short*)malloc(sizeof(short));
        bufferSize+=selda->L[sli];
        selda->T[sli]=1;
                  
    }
    fileHeaderP+=1;
    *fileHeaderP='\0';
    fileHeaderP=fileHeader;
    memset(fileHeaderP,' ',12);
    fileHeaderSize=strlen(fileHeader);
    fileHeaderSize+=2+10;
    sprintf(tempIntStr,"[%d]",fileHeaderSize);
    strncpy(fileHeaderP,tempIntStr,intValueSize(fileHeaderSize)+2);
    printf("%s\n",fileHeader);
    printf("header size:%d\n",fileHeaderSize);
    /*write it to file*/
    /*
    fwrite(fileHeader,fileHeaderSize,1,fd);
    */
    free(fileHeader);
    fileHeaderP=0;
   
   
   
    buffer=(char*)malloc(bufferSize);
    bufferP=buffer;
               
               

    /* FETCH each row selected and print the column values. */
    EXEC SQL WHENEVER NOT FOUND GOTO end_select_loop;
    getNowTime(&hour,&min,&sec,&mil);
    printf("before do the sql,time is(HOUR:%d,MIN:%d,SEC:%d,MIL:%u)\n",hour,min,sec,mil);
    for (;
    {
        EXEC SQL FETCH C USING DESCRIPTOR selda;
/*
printf("--after fetch using descriptor --\n");
printSqlda(selda);
*/
        /* Since each variable returned has been coerced to a
           character string, int, or float very little processing
           is required here.  This routine just prints out the
           values on the terminal. */
        for (sli = 0; sli < selda->F; sli++)
        {
            if(*selda->I[sli]==-1){
                /*
                printf("NULL");
                */
                memset(bufferP,' ',selda->L[sli]);
                bufferP+=selda->L[sli];
               
            }else{
                if(*selda->I[sli]==0){
                    /*
                    printf("%s",selda->V[sli]);
                    */
                    sprintf(bufferP,"%s",selda->V[sli]);
                    bufferP+=selda->L[sli];
                }else{
                    printf("have been truncated:%d ",selda->I[sli]);
                }   
            }
        }
        /*
        printf ("\n");
        printf("[%s]\n",buffer);
        */
        fwrite(buffer,bufferSize,1,fd);
        /*when end one row,reset all*/
        bufferP=buffer;
        
    }
end_select_loop:
    /*write tail*/
    fileHeader=(char*)malloc(100);
    memset(fileHeader,'\0',100);
    sprintf(fileHeader,"[%d]",sqlca.sqlerrd[2]);
    fwrite(fileHeader,sizeof(fileHeader),1,fd);
    fclose(fd);
    printf("\n%d rows retrieved\n", sqlca.sqlerrd[2]);   
    EXEC SQL ROLLBACK RELEASE;
    getNowTime(&hour2,&min2,&sec2,&mil2);
    printf("use time:");
    if(hour2<hour){
        hour-=12;
    }
        printf("%d hour,",hour2-hour);
    if(min2<min){
        
    }
    printf("after do the sql,time is(HOUR:%d,MIN:%d,SEC:%d,MIL:%u)\n",hour2,min2,sec2,mil2);      
    printUseTime(hour,min,sec,(int)mil,hour2,min2,sec2,(int)mil2);
    exit(EXIT_SUCCESS);
    return;     
                /*write tail*/
                fileHeader=(char*)malloc(100);
                memset(fileHeader,'\0',100);
                sprintf(fileHeader,"[%d]",sqlca.sqlerrd[2]);
                fwrite(fileHeader,sizeof(fileHeader),1,fd);
                fclose(fd);  
                printf("\n%d rows retrieved\n", sqlca.sqlerrd[2]);   
                EXEC SQL ROLLBACK RELEASE;
               
                getNowTime(&hour2,&min2,&sec2,&mil2);
    printf("after do the sql,time is(HOUR:%d,MIN:%d,SEC:%d,MIL:%u)\n",hour2,min2,sec2,mil2);   
                printUseTime(hour,min,sec,(int)mil,hour2,min2,sec2,(int)mil2);
                exit(EXIT_SUCCESS);
}

/*==========end main=========*/
/*---------------------------------
  */
void printSqlda(SQLDA *sqlDa){
   
    /*(long N)sli or p's max num*/
    printf("1long N)sli or p's max num:%d\n",sqlDa->N);
    /*(F)sli or p's realy num*/
    printf("6F)sli or p's realy num:%d\n",sqlDa->F);
    /*(char **V)address of sli or bv's value's address*/
    int num=sqlDa->F;
    int i=0;
    printf("2char **V)address of sli or bv's value's address\n");
    for(i=0;i<num;i++){
        printf("  address:%x,value:%s\n",sqlDa->V[0],sqlDa->V);
    }
    /*3(long *L)pointer to SLI or BV value's length*/
    printf("3long *L)pointer to SLI or BV value's length\n");
    for(i=0;i<num;i++){
        printf("  address:%x,value:%d\n",sqlDa->L,sqlDa->L);
    }
    /*4(short *T)pointer to SLI or BV value's type*/
    printf("4short *T)pointer to SLI or BV value's type\n");
    for(i=0;i<num;i++){
        printf("  address:%x,value:%d\n",sqlDa->T,sqlDa->T);
    }
    /*5(short **I)pointer to IV value's address*/
    printf("5short **I)pointer to IV value's address\n");
    for(i=0;i<num;i++){
        printf("  address:%x,value:%d\n",sqlDa->I,sqlDa->I);
    }
   
   
    /*7char **S) pointer to SLI or P name's address*/
    printf("7char **S) pointer to SLI or P name's address\n");
    for(i=0;i<num;i++){
        printf("  address:%x,value:%s\n",sqlDa->S,sqlDa->S);
    }
    /*8short *M) pointer to SLI or P name's max length*/
    printf("8short *M) pointer to SLI or P name's max length\n");
    for(i=0;i<num;i++){
        printf("  address:%x,value:%d\n",sqlDa->M,sqlDa->M);
    }
    /*9:(short *C) pointer to SLI or P name's current length*/
    printf("9:(short *C) pointer to SLI or P name's current length\n");
    for(i=0;i<num;i++){
        printf("  address:%x,value:%d\n",sqlDa->C,sqlDa->C);
    }
   
    /*-----------------------------------------------*/
    /*10:(char **X) pointer to IV name's address*/
    printf("10:(char **X) pointer to IV name's address\n");
    for(i=0;i<num;i++){
        printf("  address:%x,value:%s\n",sqlDa->X,sqlDa->X);
    }
   
   
    /*11:(*Y) pointer to IV name max length*/
    printf("11:(*Y) pointer to IV name max length\n");
    for(i=0;i<num;i++){
        printf("  address:%x,value:%d\n",sqlDa->Y,sqlDa->Y);
    }
   
    /*12:(*Z) pointer to IV name current length*/
    printf("12:(short *Z) pointer to IV name current length\n");
    for(i=0;i<num;i++){
        printf("  address:%x,value:%d\n",sqlDa->Z,sqlDa->Z);
    }
   
}
  /*------------------------------------------------*/
void sql_error(){   
    char msgbuf[512];   
    size_t msgbuf_len, msg_len;   
    msgbuf_len = sizeof(msgbuf);   
    sqlglm(msgbuf, &msgbuf_len, &msg_len);   
    printf ("\n\n%.*s\n", msg_len, msgbuf);   
    EXEC SQL WHENEVER SQLERROR CONTINUE;   
    EXEC SQL ROLLBACK WORK RELEASE;   
    exit(EXIT_FAILURE);
}
int intValueSize(int intValue){
    if(intValue>=0&&intValue<10)
       return 1;
    if(intValue>=10&&intValue<100)
       return 2;
    if(intValue>=100&&intValue<1000)
       return 3;
    if(intValue>=1000&&intValue<10000)
       return 4;
   
}

使用道具 举报

回复
论坛徽章:
22
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02马上有对象
日期:2014-02-19 11:55:14马上有钱
日期:2014-02-19 11:55:14马上有房
日期:2014-02-19 11:55:14马上有车
日期:2014-02-19 11:55:142012新春纪念徽章
日期:2012-02-13 15:10:582012新春纪念徽章
日期:2012-02-13 15:10:582012新春纪念徽章
日期:2012-02-13 15:10:582012新春纪念徽章
日期:2012-02-13 15:10:582012新春纪念徽章
日期:2012-02-13 15:10:58
20#
发表于 2005-1-25 18:39 | 只看该作者
--Try
select /*+ full(a) full(b) use_hash(a,b)*/
count(*) from test20m1 a,test20m2 b where a.empno=b.empno;

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表