浅谈SQLite——查询处理及优化
2010-06-25 00:00:00 来源:WEB开发网而对于每一层的优化,基本的理念就是对于该层循环的表,分析WHERE子句中是否有表达式能够使用其索引。
Sqlite有三种基本的扫描策略:
(1)全表扫描,这种情况通常出现在没有WHERE子句时;
(2)基于索引扫描,这种情况通常出现在表有索引,而且WHERE中的表达式又能够使用该索引的情况;
(3)基本rowid的扫描,这种情况通常出现在WHERE表达式中含有rowid的条件。该情况实际上也是对表进行的扫描。可以说,Sqlite以rowid为聚簇索引。
第一种情况比较简单,第三种情况与第二种情况没有什么本质的差别。所以,这里只对第二种情况进行详细讨论。
先来看看sqlite3WhereBegin的代码(去掉了一些无关紧要的代码):
1 /*分析where子句的所有表达式.如果表达式的形式为X <op> Y,则增加一个Y <op> X形式的虚Term,并在后面进行单独分析.
2 * */
3 exprAnalyzeAll(pTabList, pWC);
4
5 WHERETRACE(("*** Optimizer Start ***\n"));
6 //优化开始
7 for(i=iFrom=0, pLevel=pWInfo->a; i<nTabList; i++, pLevel++){
8 WhereCost bestPlan; /* Most efficient plan seen so far */
9 Index *pIdx; /* Index for FROM table at pTabItem */
10 int j; /* For looping over FROM tables */
11 int bestJ = -1; /* The value of j */
12 Bitmask m; /* Bitmask value for j or bestJ */
13 int isOptimal; /* Iterator for optimal/non-optimal search */
14
15 memset(&bestPlan, 0, sizeof(bestPlan));
16 bestPlan.rCost = SQLITE_BIG_DBL;
17
18 /*进行两次扫描:*/
19 //如果第一次扫描没有找到优化的扫描策略,此时,isOptimal ==0, bestJ ==-1,则进行第二次扫描
20 for(isOptimal=1; isOptimal>=0 && bestJ<0; isOptimal--){
21 //第一次扫描的mask ==0,表示所有表都已经准备好
22 Bitmask mask = (isOptimal ? 0 : notReady);
23 assert( (nTabList-iFrom)>1 || isOptimal );
24
25 for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
26 int doNotReorder; /* True if this table should not be reordered */
27 WhereCost sCost; /* Cost information from best[Virtual]Index() */
28 ExprList *pOrderBy; /* ORDER BY clause for index to optimize */
29
30 //对于左连接和交叉连接,不能改变嵌套的顺序
31 doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
32
33 if( j!=iFrom && doNotReorder ) //如果j == iFrom,仍要进行优化处理(此时,是第一次处理iFrom项)
34 break;
35 m = getMask(pMaskSet, pTabItem->iCursor);
36 if( (m & notReady)==0 ){//如果该pTabItem已经进行处理,则不需要再处理
37 if( j==iFrom )
38 iFrom++;
39 continue;
40 }
41 pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
42
43 {
44 //对一个表(pTabItem),找到它的可用于本次查询的最好的索引,sCost返回对应的代价
45 bestBtreeIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost);
46 }
47 if( (sCost.used¬Ready)==0
48 && (j==iFrom || sCost.rCost<bestPlan.rCost)
49 ){
50 bestPlan = sCost;
51 bestJ = j; //如果bestJ >=0,表示找到了优化的扫描策略
52 }
53 if( doNotReorder ) break;
54 }//end for
55 }//end for
56 WHERETRACE(("*** Optimizer selects table %d for loop %d\n", bestJ,
57 pLevel-pWInfo->a));
58
59 if( (bestPlan.plan.wsFlags & WHERE_ORDERBY)!=0 ){//不需要进行排序操作
60 *ppOrderBy = 0;
61 }
62 //设置该层选用的查询策略
63 andFlags &= bestPlan.plan.wsFlags;
64 pLevel->plan = bestPlan.plan;
65
66 //如果可以使用索引,则设置索引对应的游标的下标
67 if( bestPlan.plan.wsFlags & WHERE_INDEXED ){
68 pLevel->iIdxCur = pParse->nTab++;
69 }else{
70 pLevel->iIdxCur = -1;
71 }
72 notReady &= ~getMask(pMaskSet, pTabList->a[bestJ].iCursor);
73 //该层对应的FROM的表项,即该层循环是对哪个表进行的操作.
74 pLevel->iFrom = (u8)bestJ;
75
76 }
77 //优化结束
78 WHERETRACE(("*** Optimizer Finished ***\n"));
79
更多精彩
赞助商链接