非常教程

Sqlite参考手册

其他 | Miscellaneous

EXPLAIN QUERY PLAN

1. EXPLAIN QUERY PLAN命令

1.1.表和索引扫描

1.2.临时排序B树

1.3.子查询

1.4.复合查询

2.示例代码

警告:EXPLAIN QUERY PLAN命令返回的数据仅用于交互式调试。输出格式可能会在SQLite版本之间改变。应用程序不应该依赖于EXPLAIN QUERY PLAN命令的输出格式。

EXPLAIN QUERY PLAN SQL命令用于获取SQLite用于实现特定SQL查询的策略或计划的高级描述。最重要的是,EXPLAIN QUERY PLAN报告查询使用数据库索引的方式。本文档是了解和解释EXPLAIN QUERY PLAN输出的指南。背景信息单独提供:

  • 关于查询优化器的说明。
  • 索引如何工作。
  • 下一代查询计划器。

EXPLAIN QUERY PLAN命令每个返回零或多行四列。列名是“selectid”,“order”,“from”,“detail”。前三列包含一个整数值。最后一列“详细信息”包含一个文本值,其中包含大部分有用的信息。

EXPLAIN QUERY PLAN在SELECT语句中最为有用,但也可能与其他从数据库表读取数据的语句(例如UPDATE,DELETE,INSERT INTO ... SELECT)一起出现。

1.1.表和索引扫描

处理SELECT(或其他)语句时,SQLite可以通过多种方式从数据库表中检索数据。它可以扫描表中的所有记录(全表扫描),根据rowid索引扫描表中记录的连续子集,扫描数据库索引中连续的条目子集或使用组合的上述策略在一次扫描中。这里详细描述了SQLite可以从表或索引中检索数据的各种方式。

对于查询读取的每个表,EXPLAIN QUERY PLAN的输出包括一个记录,“详细信息”列中的值以“SCAN”或“SEARCH”开头。“扫描”用于全表扫描,包括SQLite按照索引定义的顺序遍历表中所有记录的情况。“SEARCH”表示只有一部分表格行被访问。每个SCAN或SEARCH记录都包含以下信息:

  • 表格数据的名称是从中读取的。
  • 是否使用索引或自动索引。
  • 覆盖指数优化是否适用。
  • WHERE子句中的哪些条款用于建立索引。

例如,以下EXPLAIN QUERY PLAN命令对通过对表t1执行全表扫描而实现的SELECT语句进行操作:

sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; 
0|0|0|SCAN TABLE t1

上面的例子显示SQLite选择全表扫描将访问表中的所有行。如果查询能够使用索引,则SCAN / SEARCH记录将包括索引的名称,并且对于SEARCH记录,指示如何识别访问的行的子集。例如:

sqlite> CREATE INDEX i1 ON t1(a);
sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1;
0|0|0|SEARCH TABLE t1 USING INDEX i1

前面的例子中,SQLite使用索引“i1”来优化表单(a =?)的WHERE子句项 - 在本例中为“a = 1”。前面的例子不能使用覆盖索引,但是下面的例子可以,而且这个事实也反映在输出中:

sqlite> CREATE INDEX i2 ON t1(a, b);
sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; 
0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)

SQLite中的所有连接都使用嵌套扫描来实现。当使用EXPLAIN QUERY PLAN分析具有连接的SELECT查询时,将为每个嵌套循环输出一个SCAN或SEARCH记录。例如:

sqlite> EXPLAIN QUERY PLAN SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2;
0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)
0|1|1|SCAN TABLE t2

输出的第二列(“order”列)指示嵌套顺序。在这种情况下,使用索引i2扫描表t1是外部循环(顺序= 0),而表t2(order = 1)的全部表扫描是内部循环。第三列(from“”)表示SELECT语句的FROM子句中与每次扫描相关的表的位置。在上面的例子中,表t1占据了FROM子句中的第一个位置,所以值列的“from”在第一条记录中为0。表t2位于第二个位置,因此相应SCAN记录的“from”列设置为1.在以下示例中,SELECT的FROM子句中的t1和t2的位置相反。查询策略保持不变,但“from”

sqlite> EXPLAIN QUERY PLAN SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2;
0|0|1|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)
0|1|0|SCAN TABLE t2

如果查询的WHERE子句包含OR表达式,那么SQLite可能会使用“OR by union”策略(这里也有描述)。在这种情况下,将有两个SEARCH记录,每个索引一个,在“order”和“from”列中都有相同的值。例如:

sqlite> CREATE INDEX i3 ON t1(b);
sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2;
0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)
0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?)

1.2.临时排序B树

如果SELECT查询包含ORDER BY,GROUP BY或DISTINCT子句,则SQLite可能需要使用临时b-树结构对输出行进行排序。或者,它可能会使用索引。使用索引几乎总是比执行排序更高效。如果需要临时B树,则将记录添加到EXPLAIN QUERY PLAN输出中,并将“detail”字段设置为“USE TEMP B-TREE FOR xxx”形式的字符串值,其中xxx是“ORDER BY“,”GROUP BY“或”DISTINCT“。例如:

sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c; 
0|0|0|SCAN TABLE t2
0|0|0|USE TEMP B-TREE FOR ORDER BY

在这种情况下,可以通过在t2(c)上创建索引来避免使用临时b树,如下所示:

sqlite> CREATE INDEX i4 ON t2(c);
sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c; 
0|0|0|SCAN TABLE t2 USING INDEX i4

1.3.子查询

在上面的所有示例中,第一列(列“selectid”)始终设置为0.如果查询包含子选择(作为FROM子句的一部分或作为SQL表达式的一部分),则EXPLAIN QUERY PLAN还包括每个子选择的报告。每个子选择被分配一个不同的,非零的“选择”值。顶级SELECT语句始终分配有选项ID值0.例如:

sqlite> EXPLAIN QUERY PLAN SELECT (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2;
0|0|0|SCAN TABLE t2
0|0|0|EXECUTE SCALAR SUBQUERY 1
1|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)
0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2
2|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?)

上面的示例包含一对分配了精选值1和2的标量子查询。除了SCAN记录外,还有2个与顶级子查询(selectid 0)关联的“EXECUTE”记录,表示子查询1和2被执行通过标量上下文中的顶级查询。与标量子查询2相关联的EXECUTE记录中的CORRELATED限定符指示查询必须针对顶级查询访问的每一行单独运行。它在与子查询1相关的记录中缺失意味着子查询仅运行一次并且结果被缓存。换句话说,子查询2可能更关键,因为它可能运行很多次,而子查询1只运行一次。

除非应用展平优化,否则,如果子查询出现在SELECT语句的FROM子句中,SQLite将执行子查询并将结果存储在临时表中。然后它使用临时表的内容代替子查询来执行父查询。这在EXPLAIN QUERY PLAN的输出中显示,通过将“SCAN SUBQUERY”记录替换为FROM子句中通常出现的每个元素的“SCAN TABLE”记录。例如:

sqlite> EXPLAIN QUERY PLAN SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x;
1|0|0|SCAN TABLE t1 USING COVERING INDEX i2
0|0|0|SCAN SUBQUERY 1
0|0|0|USE TEMP B-TREE FOR GROUP BY

如果在SELECT语句的FROM子句中的子查询上使用了展平优化,则EXPLAIN QUERY PLAN的输出反映了这一点。例如,即使在顶层SELECT的FROM子句中存在子查询,下面也没有“SCAN SUBQUERY”记录。相反,由于flattening优化在这种情况下适用,EXPLAIN QUERY PLAN报告显示顶级查询是使用表t1和t2的嵌套循环连接实现的。

sqlite> EXPLAIN QUERY PLAN SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1;
0|0|0|SEARCH TABLE t2 USING INDEX i4 (c=?)
0|1|1|SCAN TABLE t1

1.4.复合查询

复合查询的每个组件查询(UNION,UNION ALL,EXCEPT或INTERSECT)都被分配了自己的选择标识并单独报告。输出用于标识操作的父级(复合查询)的单个记录,以及是否使用临时B树来实现它。例如:

sqlite> EXPLAIN QUERY PLAN SELECT a FROM t1 UNION SELECT c FROM t2;
1|0|0|SCAN TABLE t1
2|0|0|SCAN TABLE t2
0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)

上述输出中的“USING TEMP B-TREE”子句表示临时b树结构用于实现两个子选择结果的UNION。如果不需要临时B树,如下例所示,该子句不存在。

sqlite> EXPLAIN QUERY PLAN SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1;
1|0|0|SCAN TABLE t1 USING COVERING INDEX i2
2|0|0|SCAN TABLE t2
2|0|0|USE TEMP B-TREE FOR ORDER BY
0|0|0|COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)

有时,在大型应用程序中,修改代码以生成EXPLAIN QUERY PLAN命令可能不便于调查的SELECT查询。从交互式调试会话中,可能几乎不可能。在这些情况下,类似于以下的函数可能会有用。此特定函数将SQLite语句句柄作为参数传递,并将相应的EXPLAIN QUERY PLAN报告输出到标准输出。应用程序特定版本可能会将报告输出到应用程序日志或类似文件

/*
** Argument pStmt is a prepared SQL statement. This function compiles
** an EXPLAIN QUERY PLAN command to report on the prepared statement,
** and prints the report to stdout using printf().
*/
int printExplainQueryPlan(sqlite3_stmt *pStmt){
  const char *zSql;               /* Input SQL */
  char *zExplain;                 /* SQL with EXPLAIN QUERY PLAN prepended */
  sqlite3_stmt *pExplain;         /* Compiled EXPLAIN QUERY PLAN command */
  int rc;                         /* Return code from sqlite3_prepare_v2() */

  zSql = sqlite3_sql(pStmt);
  if( zSql==0 ) return SQLITE_ERROR;

  zExplain = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zSql);
  if( zExplain==0 ) return SQLITE_NOMEM;

  rc = sqlite3_prepare_v2(sqlite3_db_handle(pStmt), zExplain, -1, &pExplain, 0);
  sqlite3_free(zExplain);
  if( rc!=SQLITE_OK ) return rc;

  while( SQLITE_ROW==sqlite3_step(pExplain) ){
    int iSelectid = sqlite3_column_int(pExplain, 0);
    int iOrder = sqlite3_column_int(pExplain, 1);
    int iFrom = sqlite3_column_int(pExplain, 2);
    const char *zDetail = (const char *)sqlite3_column_text(pExplain, 3);

    printf("%d %d %d %s\n", iSelectid, iOrder, iFrom, zDetail);
  }

  return sqlite3_finalize(pExplain);
}
 SQLite在公共领域。

其他 | Miscellaneous相关

1.35% Faster Than The Filesystem
2.8+3 Filenames
3.An Asynchronous I/O Module For SQLite
4.Appropriate Uses For SQLite
5.Architecture of SQLite
6.Atomic Commit In SQLite
7.Automatic Undo/Redo With SQLite
8.Benefits of SQLite As A File Format
9.Change in Default Page Size in SQLite Version 3.12.0
10.Clustered Indexes and the WITHOUT ROWID Optimization
11.Compile-time Options
12.Constraint Conflict Resolution in SQLite
13.Custom Builds Of SQLite
14.Deterministic SQL Functions
15.Distinctive Features Of SQLite
16.Features Of SQLite
17.File Format Changes in SQLite
18.Full-Featured SQL
19.High Reliability
20.Hints for Debugging SQLite
21.How SQLite Is Tested
22.How To Compile SQLite
23.How To Download Canonical SQLite Source Code
24.Imposter Tables
25.In-Memory Databases
26.Indexes On Expressions
27.Internal Versus External BLOBs
28.Isolation In SQLite
29.Long Term Support
30.Maintaining Private Branches Of SQLite
31.Many Small Queries Are Efficient In SQLite
32.Measuring and Reducing CPU Usage in SQLite
33.Memory-Mapped I/O
34.NULL Handling in SQLite
35.Partial Indexes
36.Pointer Passing Interfaces
37.Powersafe Overwrite
38.Release History Of SQLite
39.Result and Error Codes
40.Row Values
41.Rowid Tables
42.Run-Time Loadable Extensions
43.SQL Features That SQLite Does Not Implement
44.sqldiff.exe: Database Difference Utility
45.SQLite As An Application File Format
46.SQLite Autoincrement
47.SQLite Backup API
48.SQLite Changes From Version 3.4.2 To 3.5.0
49.SQLite Changes From Version 3.5.9 To 3.6.0
50.SQLite Database Speed Comparison
51.SQLite File IO Specification
52.SQLite Frequently Asked Questions
53.SQLite In 5 Minutes Or Less
54.SQLite is a Self Contained System
55.SQLite Is Serverless
56.SQLite Is Transactional
57.SQLite Library Footprint
58.SQLite Shared-Cache Mode
59.SQLite Unlock-Notify API
60.SQLite Version 3 Overview
61.SQLite: Single File Database
62.Temporary Files Used By SQLite
63.TH3
64.The COMPLETION() Table-Valued Function
65.The CSV Virtual Table
66.The dbhash.exe Utility Program
67.The DBSTAT Virtual Table
68.The Error And Warning Log
69.The generate_series Table-Valued Function
70.The OS Backend (VFS) To SQLite
71.The Spellfix1 Virtual Table
72.The SQLite Amalgamation
73.The SQLite Bytecode Engine
74.The sqlite3_analyzer.exe Utility Program
75.The SQLITE_STMT Virtual Table
76.The UNION Virtual Table
77.The Virtual Database Engine of SQLite
78.Uniform Resource Identifiers
79.Using SQLite In Multi-Threaded Applications
80.Version Numbers in SQLite
81.What If OpenDocument Used SQLite?
82.Why Is SQLite Coded In C
83.Zero-Configuration
Sqlite

SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来

主页 https://sqlite.org/
源码 https://www.sqlite.org/src/
发布版本 3.21.0

Sqlite目录

1.C界面 | C Interface
2.C Interface: Session Module
3.CLI
4.数据库文件表 | Database File Format
5.数据类 | Datatypes
6.动态内存分配 | Dynamic Memory Allocation
7.外键约束 | Foreign Key Constraints
8.全文索引 | Full-Text Search
9.损坏方式 | How To Corrupt
10.JSON
11.语言 | Language
12.局限性 | Limits
13.锁定和并发 | Locking and Concurrency
14.其他 | Miscellaneous
15.PRAGMA Statements
16.查询计划程序 | Query Planner
17.R*Tree Module
18.RBU Extension
19.语法图 | Syntax Diagrams
20.Tcl Interface
21.虚拟表机制 | Virtual Table Mechanism
22.预写日志 | Write-Ahead Logging
23.SQL 教程
24.SQL 简介
25.SQL 语法
26.SQL DELETE 语句
27.SQL UPDATE 语句
28.SQL NOT NULL 约束
29.SQL 约束
30.SQL CREATE TABLE 语句
31.SQL CREATE DATABASE 语句
32.SQL INSERT INTO SELECT 语句
33.SQL SELECT INTO 语句
34.SQL CREATE VIEW、REPLACE VIEW、 DROP VIEW 语句
35.SQL AUTO INCREMENT 字段
36.SQL ALTER TABLE 语句
37.SQL 撤销索引、表以及数据库
38.SQL CREATE INDEX 语句
39.SQL DEFAULT 约束
40.SQL CHECK 约束
41.SQL FOREIGN KEY 约束
42.SQL PRIMARY KEY 约束
43.SQL UNIQUE 约束
44.SQL 通用数据类型
45.SQL ISNULL()、NVL()、IFNULL() 和 COALESCE() 函数
46.SQL NULL 值 – IS NULL 和 IS NOT NULL
47.SQL Server 和 MySQL 中的 Date 函数
48.SQL MS Access、MySQL 和 SQL Server 数据类型
49.SQL 函数
50.SQL 总结
51.SQL 主机
52.SQL 快速参考
53.SQL ROUND() 函数
54.SQL Server GETDATE() 函数
55.MySQL DATE_FORMAT() 函数
56.MySQL DATEDIFF() 函数
57.MySQL DATE_SUB() 函数
58.MySQL DATE_ADD() 函数
59.MySQL EXTRACT() 函数
60.MySQL DATE() 函数
61.MySQL CURTIME() 函数
62.MySQL CURDATE() 函数
63.MySQL NOW() 函数
64.SQL Server CONVERT() 函数
65.SQL Server DATEDIFF() 函数
66.SQL Server DATEADD() 函数
67.SQL Server DATEPART() 函数
68.SQLite 命令
69.SQLite 安装
70.SQLite 简介
71.SQLite 运算符
72.SQLite Select 语句
73.SQLite 删除表
74.SQLite 创建表
75.SQLite Insert 语句
76.SQLite 分离数据库
77.SQLite 附加数据库
78.SQLite 创建数据库
79.SQLite 数据类型
80.SQLite 语法
81.SQLite Order By
82.SQLite Limit 子句
83.SQLite Glob 子句
84.SQLite Like 子句
85.SQLite Delete 语句
86.SQLite Update 语句
87.SQLite AND/OR 运算符
88.SQLite Where 子句
89.SQLite 表达式
90.SQLite Distinct 关键字
91.SQLite Having 子句
92.SQLite Group By
93.SQLite Join
94.SQLite 约束
95.SQLite PRAGMA
96.SQLite 事务
97.SQLite 视图
98.SQLite Truncate Table
99.SQLite Alter 命令
100.SQLite Indexed By