数据库的性能优化行业里面广泛偏少,今天这篇但愿给你们带来点帮助html
咱们在使用SQLite进行数据存储查询的时候,要进行查询优化,这里就会用到索引,C端的数据量大部分状况下面虽然不是很大,但良好的索引创建习惯每每会带来不错的查询性能提高,同时在未知的未来经得住更大数据的考验,那如何优化数据库查询呢,下面咱们用例子一一演示下。sql
先建个测试表table1,包含了三个索引:数据库
sqlite> .schem CREATE TABLE table1(id integer primary key not null default 0,a integer,b integer, c integer); CREATE INDEX a_i on table1 (a); CREATE INDEX a_i2 on table1 (a,b); CREATE INDEX a_i3 on table1 (c);
在常见的数据库系统里面,进行SQL查询检验都是用explain关键字,好比:性能优化
sqlite> explain select * from table1; addr opcode p1 p2 p3 p4 p5 comment ---- ------------- ---- ---- ---- ------------- -- ------------- 0 Init 0 10 0 00 Start at 10 1 OpenRead 0 2 0 4 00 root=2 iDb=0; table1 2 Rewind 0 9 0 00 3 Rowid 0 1 0 00 r[1]=rowid 4 Column 0 1 2 00 r[2]=table1.a 5 Column 0 2 3 00 r[3]=table1.b 6 Column 0 3 4 00 r[4]=table1.c 7 ResultRow 1 4 0 00 output=r[1..4] 8 Next 0 3 0 01 9 Halt 0 0 0 00 10 Transaction 0 0 4 0 01 usesStmtJournal=0 11 Goto 0 1 0 00
立马就会获得输出,这些输出表示SQLite执行这条SQL用到的每句指令,这个其实不怎么直观,咱们用到更多的是EXPLAIN QUERY PLAN,以下:性能
sqlite> explain QUERY PLAN select * from table1; 0|0|0|SCAN TABLE table1
这条SQL语句是查询了整张表,因此结果关键字SCAN表示要完整遍历,这种效率是最低的,接下来咱们试试加个查询条件:测试
sqlite> explain QUERY PLAN select * from table1 where a=1; 0|0|0|SEARCH TABLE table1 USING INDEX a_i2 (a=?)
加上where a=1以后关键字变成了SEARCH,表示再也不须要遍历了,而是使用了索引进行了部分检索,另外这条输出还有更多信息,好比使用了索引a_i2,而括号里面的a=?则表示是这个查询条件引发的大数据
咱们稍微修改下SQL:优化
sqlite> explain QUERY PLAN select a from table1 where a=1; 0|0|0|SEARCH TABLE table1 USING COVERING INDEX a_i (a=?)
把select 变成了select a,发现explain输出有细微变化,从INDEX变成了COVERING INDEX,CONVERING INDEX表示直接使用索引查询就能够获得结果,不须要再次回查数据表,这样效率更高。而以前的查询由于是使用,索引里面只有a记录,因此必需要查询原始记录才能获得b,c字段。咱们再试下这条SQL:code
sqlite> explain QUERY PLAN select a,b from table1 where a=1 and b=1; 0|0|0|SEARCH TABLE table1 USING COVERING INDEX a_i2 (a=? AND b=?)
赞成由于索引a_i2已经包含a和b了,因此也是使用CONVERING INDEX。那有同窗可能会问了,那咱们建索引的时候都把其余字段都加进去呗,虽然查询用不到,但不用二次查询原始记录效率高。理论上这样是可行的,但这里有个重要问题就是数据冗余太严重了,致使索引和原始数据同样大,在海量数据存储的数据库里面磁盘消耗是个问题,因此如何选择可能要作个平衡。sqlite
接下来咱们把and换成or:
sqlite> explain QUERY PLAN select a,b from table1 where a=1 or b=1; 0|0|0|SCAN TABLE table1 USING COVERING INDEX a_i2
发现又变回SCAN了,但仍然使用到了索引a_i2,对比下这条SQL:
sqlite> explain QUERY PLAN select a,b from table1 where a=1; 0|0|0|SEARCH TABLE table1 USING COVERING INDEX a_i2 (a=?)
多了个查询条件b=1以后效率变差了,这是为何呢?这里要引出咱们建立索引使用的最关键的原则:前缀索引。
索引通常是使用B树,前缀索引简单来说,就是要想能使用这个索引,查询条件必须知足索引创建涉及到的字段,而且和查询使用的顺序一致。
咱们回头看刚才那个or的例子,对于查询条件a=1,他能使用a_i2(a,b)这个索引,由于索引顺序也是a开头的。但or的例子里面还或上一个查询条件b=1,对于这个查询就没有索引能够用了,由于没有b开头的索引存在。a_i2(a,b)这个索引里面虽然有b,但b对于b=1这个查询条件来讲不是在前面,不知足前缀索引原则。
而对于刚才那个and的例子,则可以彻底使用索引,由于存在索引a_i2(a,b),能够想象成先按索引a过滤数据,剩下数据再用索引b过滤数据。对于and条件来讲,索引里面字段的顺序换一下也是没有关系的,数据库会自动优化选择,好比:
sqlite> .schem CREATE INDEX a_i22 on table2 (b,a); sqlite> explain QUERY PLAN select a,b from table2 where a=1 and b=1; 0|0|0|SEARCH TABLE table2 USING COVERING INDEX a_i22 (b=? AND a=?)
若是or查询也要充分使用索引,聪明的读者必定想到了,那就是要建2个索引,以下:
CREATE TABLE table3(id integer primary key not null default 0,a integer,b integer, c integer); CREATE INDEX a_i222 on table3(a); CREATE INDEX a_i2222 on table3(b); sqlite> explain QUERY PLAN select a,b from table3 where a=1 or b=1; 0|0|0|SEARCH TABLE table3 USING INDEX a_i222 (a=?) 0|0|0|SEARCH TABLE table3 USING INDEX a_i2222 (b=?)
咱们再来看一个进阶的,加上一个排序:
CREATE TABLE table1(id integer primary key not null default 0,a integer,b integer, c integer); CREATE INDEX a_i2 on table1 (a,b); sqlite> explain QUERY PLAN select a,b from table1 where a=1 order by b; 0|0|0|SEARCH TABLE table1 USING COVERING INDEX a_i2 (a=?) CREATE TABLE table3(id integer primary key not null default 0,a integer,b integer, c integer); CREATE INDEX a_i222 on table3(a); CREATE INDEX a_i2222 on table3(b); sqlite> explain QUERY PLAN select a,b from table3 where a=1 order by b; 0|0|0|SEARCH TABLE table3 USING INDEX a_i222 (a=?) 0|0|0|USE TEMP B-TREE FOR ORDER BY
对比这2个查询,发现下面这个多了个USE TEMP B-TREE FOR ORDER BY。对于第一个查询来讲,咱们能够看到排序也是一样知足前缀索引原则(先按索引a过滤数据,剩下数据用索引b排序)。对于第二个查询来讲,由于不知足这个原则致使多了个临时表来作排序。看到这里你们应该理解前缀索引的意思了。
咱们再看这个样子,把查询条件和排序换下:
sqlite> explain QUERY PLAN select a,b from table1 where b=1 order by a; 0|0|0|SCAN TABLE table1 USING COVERING INDEX a_i2
显然不知足前缀索引原则了,由于须要先按索引b过滤数据,但b不是第一个。
常规的查询语句大部分是and,or,order的组合使用,只须要掌握上面说的原则,必定能写出高性能的数据库查询语句来。
而对于更高级的一些连表能够继续翻阅官方文档: