Android SQLite数据库查询优化方法

数据库的性能优化行业里面普遍偏少,今天这篇希望给大家带来点帮助

我们在使用SQLite进行数据存储查询的时候,要进行查询优化,这里就会用到索引,C端的数据量大部分情况下面虽然不是很大,但良好的索引建立习惯往往会带来不错的查询性能提升,同时在未知的将来经得住更大数据的考验,那如何优化数据库查询呢,下面我们用例子一一演示下。

y'h

先建个测试表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:

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。那有同学可能会问了,那我们建索引的时候都把其他字段都加进去呗,虽然查询用不到,但不用二次查询原始记录效率高。理论上这样是可行的,但这里有个重要问题就是数据冗余太严重了,导致索引和原始数据一样大,在海量数据存储的数据库里面磁盘消耗是个问题,所以如何选择可能要做个平衡。

接下来我们把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的组合使用,只需要掌握上面说的原则,一定能写出高性能的数据库查询语句来。

而对于更高级的一些连表可以继续翻阅官方文档:

https://www.sqlite.org/eqp.html

https://www.sqlite.org/lang_explain.html

更多文章请关注公众号:安卓之美

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容