SQLite3源程序分析之查询处理及优化

本文深入分析SQLite3的查询处理,包括语法分析生成语法树,重点讲解了执行计划的生成过程,如sqlite3WhereBegin、selectInnerLoop和sqlite3WhereEnd函数的作用,并探讨了SQLite的代价模型。示例SQL语句展示了从语法树到OPCODE的转换,揭示了SQLite如何进行查询优化,如全表扫描、索引利用等策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SQLite3源程序分析之查询处理及优化

前言

  查询处理及优化是关系数据库得以流行的根本原因,也是关系数据库系统最核心的技术之一。SQLite的查询处理模块很精致,而且很容易移植到不支持SQL的存储引擎(Berkeley DB最新的版本已经将其完整的移植过来)。
  查询处理一般来说,包括词法分析、语法分析、语义分析、生成执行计划以及执行计划几个部分。SQLite的词法分析器是手工写的(比较简单),语法分析器由Lemon生成,语义分析主要是进行语义方面的一些检查,比如table是否存在等。而执行计划的生成及执行是最核心的两部分,也是相对比较复杂、有点技术含量的部分。SQLite的执行计划采用了虚拟机的思想,实际上,这种基于虚拟机的思想并非SQLite所独有,但是,SQLite将其发挥到了极致,它生成的执行计划非常详细,而且易读(不得不佩服D. Richard Hipp在编译理论方面的功底)。

1、语法分析——语法树

  语法分析的主要任务是对用户输入的SQL语句进行语法检查,然后生成一个包含所有信息的语法树。对于SELECT语句,这个语法树最终由结构体Select表示:

复制代码
struct Select {
     
     
  ExprList *pEList;      /* The fields of the result 结果的字段 */
  u8 op;                 /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
  char affinity;         /* MakeRecord with this affinity for SRT_Set */
  u16 selFlags;          /* Various SF_* values */
  SrcList *pSrc;         /* The FROM clause */
  Expr *pWhere;          /* The WHERE clause */
  ExprList *pGroupBy;    /* The GROUP BY clause */
  Expr *pHaving;         /* The HAVING clause */
  ExprList *pOrderBy;    /* The ORDER BY clause */
  Select *pPrior;        /* Prior select in a compound select statement 在一个复合选择语句中的优先选择 */
  Select *pNext;         /* Next select to the left in a compound */
  Select *pRightmost;    /* Right-most select in a compound select statement 在一个复合选择语句中的最右边的选择*/
  Expr *pLimit;          /* LIMIT expression. NULL means not used. */
  Expr *pOffset;         /* OFFSET expression. NULL means not used. */
  int iLimit, iOffset;   /* Memory registers holding LIMIT & OFFSET counters */
  int addrOpenEphm[3];   /* OP_OpenEphem opcodes related to this select */
};
复制代码

  该结构体中,pEList是结果列的语法树;pSrc为FROM子句的语法树;pWhere为WHERE部分的语法树。

  select语法分析最终在sqlite3SelectNew中完成:

复制代码
Select *sqlite3SelectNew(
  Parse *pParse,        /* Parsing context 解析上下文 */
  ExprList *pEList,     /* which columns to include in the result 在结果中包含哪些列 */
  SrcList *pSrc,        /* the FROM clause -- which tables to scan */
  Expr *pWhere,         /* the WHERE clause */
  ExprList *pGroupBy,   /* the GROUP BY clause */
  Expr *pHaving,        /* the HAVING clause */
  ExprList *pOrderBy,   /* the ORDER BY clause */
  int isDistinct,       /* true if the DISTINCT keyword is present */
  Expr *pLimit,         /* LIMIT value.  NULL means not used */
  Expr *pOffset         /* OFFSET value.  NULL means no offset */
){
  Select *pNew;
  Select standin;
  sqlite3 *db = pParse->db;
  pNew = sqlite3DbMallocZero(db, sizeof(*pNew) );
  assert( db->mallocFailed || !pOffset || pLimit ); /* OFFSET implies LIMIT */
  if( pNew==0 ){
    pNew = &standin;
    memset(pNew, 0, sizeof(*pNew));
  }
  if( pEList==0 ){
    pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ALL,0));
  }
  pNew->pEList = pEList;
  pNew->pSrc = pSrc;
  pNew->pWhere = pWhere;
  pNew->pGroupBy = pGroupBy;
  pNew->pHaving = pHaving;
  pNew->pOrderBy = pOrderBy;
  pNew->selFlags = isDistinct ? SF_Distinct : 0;
  pNew->op = TK_SELECT;
  pNew->pLimit = pLimit;
  pNew->pOffset = pOffset;
  assert( pOffset==0 || pLimit!=0 );
  pNew->addrOpenEphm[0] = -1;
  pNew->addrOpenEphm[1] = -1;
  pNew->addrOpenEphm[2] = -1;
  if( db->mallocFailed ) {
    clearSelect(db, pNew);
    if( pNew!=&standin ) sqlite3DbFree(db, pNew);
    pNew = 0;
  }
  return pNew;
}
复制代码

  以上函数主要是将之前得到的各个子语法树汇总到Select结构体,并根据该结构,进行语义分析及执行计划的生成等工作。

  示例(贯穿全文)

复制代码
explain select s.sname,c.cname,sc.grade from students s join sc join course c on s.sid=sc.sid and sc.cid = c.cid;
0|Trace|0|0|0||00|
1|Goto|0|35|0||00|
//////////////////////////(1)////////////////////////////
2|OpenRead|0|3|0|2|00|students  #打开students表
3|OpenRead|1|7|0|3|00|sc      #打开sc表
4|OpenRead|3|8|0|keyinfo(2,BINARY,BINARY)|00|sqlite_autoindex_sc_1 #sc的索引
5|OpenRead|2|5|
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值