SQLite表花费时间在LIKE查询中获取logging
场景 :数据库是sqlite(需要encryption数据库中的logging,因此使用iOS的SQL密码API)
数据库中有一个名为partnumber的表,其中包含模式,如下所示:
CREATE TABLE partnumber ( objid varchar PRIMARY KEY, description varchar, make varchar, model varcha, partnumber varchar, SSOKey varchar, PMOKey varchar )
该表包含大约80K条logging。
用户界面视图中有3个文本字段,用户可以在其中inputsearch条件,并在用户input字母后立即进行search。
3个文本字段是:txtFieldDescription,txtFieldMake和txtFieldModel。
假设第一个用户在txtFieldDescription中inputsearch词作为“monitor”。 所以,每个字母将执行的查询是:
1。
SELECT DISTINCT description COLLATE NOCASE FROM partnumber where description like '%m%'
2。
SELECT DISTINCT description COLLATE NOCASE FROM partnumber where description like '%mo%'
3。
SELECT DISTINCT description COLLATE NOCASE FROM partnumber where description like '%mon%'
4。
SELECT DISTINCT description COLLATE NOCASE FROM partnumber where description like '%moni%'
5。
SELECT DISTINCT description COLLATE NOCASE FROM partnumber where description like '%monit%'
6。
SELECT DISTINCT description COLLATE NOCASE FROM partnumber where description like '%monito%'
7。
SELECT DISTINCT description COLLATE NOCASE FROM partnumber where description like '%monitor%'
到现在为止还挺好。 假设现在用户想要search模型(txtFieldDescription仍然包含“监视器”)。 所以用户点击txtFieldModel。 一旦用户点击模型,一个查询被激发为:
SELECT DISTINCT model COLLATE NOCASE FROM partnumber where description like '%monitor%'
此查询将返回说明包含监视器(在任何位置)的logging的所有模型。
现在,如果用户想要search包含单词'sony'的所有模型(描述字段仍然包含监视器),那么每个字母将被执行的查询是:
1。
SELECT DISTINCT model COLLATE NOCASE FROM partnumber WHERE model like '%s%' AND description like '%monitor%'
2。
SELECT DISTINCT model COLLATE NOCASE FROM partnumber WHERE model like '%so%' AND description like '%monitor%'
3。
SELECT DISTINCT model COLLATE NOCASE FROM partnumber WHERE model like '%son%' AND description like '%monitor%'
4。
SELECT DISTINCT model COLLATE NOCASE FROM partnumber WHERE model like '%sony%' AND description like '%monitor%'
现在,如果用户点击txtFieldMake并inputsearch词为'1980',那么被解雇的查询是:
1。
SELECT DISTINCT make COLLATE NOCASE FROM partnumber WHERE make like '%1%' AND model like '%sony%' AND description like '%monitor%'
2。
SELECT DISTINCT make COLLATE NOCASE FROM partnumber WHERE make like '%19%' AND model like '%sony%' AND description like '%monitor%'
3。
SELECT DISTINCT make COLLATE NOCASE FROM partnumber WHERE make like '%198%' AND model like '%sony%' AND description like '%monitor%'
4。
SELECT DISTINCT make COLLATE NOCASE FROM partnumber WHERE make like '%1980%' AND model like '%sony%' AND description like '%monitor%'
这里,从txtFieldDescription转换到txtFieldModel或txtFieldModel到txtFieldMake的时间延迟太大,在txtFieldModel和txtFieldMake中,input的字母在5或6秒后(在查询处理之后)显示,因此光标在那里挂起。
在分析时,我发现在like关键字(如'%monitor%')中的search词之前的通配符会降低执行速度。 而在这种情况下,它们之间可能有多达3个像AND这样的关键字,因此执行时间肯定会增加。 而且,在开始时使用通配符否定索引。
几个附加信息:
-
总logging数〜80K
-
每次在表partnumber(〜80K)上运行SELECT查询
-
我执行的一些查询的结果是:
Sqlite> SELECT count(DISTINCT description COLLATE NOCASE) from partnumber; Result is: 2599 Sqlite> SELECT count(DISTINCT make COLLATE NOCASE) from partnumber; Result is: 7129 Sqlite> SELECT count(DISTINCT model COLLATE NOCASE) from partnumber; Result is: 64644 Sqlite> SELECT count(objid) from partnumber; Result is: 82135
-
指数创build如下:
CREATE INDEX index_description ON partnumber (description collate nocase) CREATE INDEX index_make ON partnumber (make collate nocase) CREATE INDEX index_model ON partnumber (model collate nocase)
一些提高绩效的select:
-
由于不同描述的计数只有2599,而make只有7129,所以表可以拆分成不同的表,其中一个包含DISTINCT描述COLLATE NOCASE输出(共2599行),另一个包含DISTINCT使COLLATE NOCASE(总数7129行)。 就模型而言,为它创build一个不同的表将无济于事,因为行数〜64644几乎等于总logging数〜82135。 但是这种方法的问题是我不知道如何在这些表中进行search,每个表中必须存在哪些列以及必须创build多less个表。 如果用户input一些描述,然后input模型,然后再input一个新的描述。
-
由于此select查询的结果显示在UITableView中,并且用户每次最多可以看到5行。 因此,我们可以将返回的行数限制为500,当用户滚动时,可以提取下一个500,直到最后一次search到的logging。
但这里的问题是虽然我只需要500条logging,但是我将不得不search整个表(SCAN〜80Klogging)。 因此,我需要一个查询,将首先search只有前10%的表,并返回前500行,然后下一个500,直到前10%的logging都search,然后下一个10%,然后下一个10%,直到80000logging是(需要以10-10%的logging进行search)。
-
如果80Klogging表可以分成4个20Klogging表,然后同时在不同的后台线程中对所有4个表进行search,得到结果集。 但是在这里,我不知道如何在4个不同的线程(批次执行)中运行查询,何时结合结果以及如何知道所有线程已经完成执行。
-
如果我可以用另一个返回相同结果但是执行速度更快的函数replace%monitor%,并且使用该函数不会影响索引的使用(也就是说,不会使用索引) ,那么执行可能会变得更快。 如果任何人都可以在sqlite中build议我这样一个函数,那么我可以继续这个方法。
如果你可以帮助我实现这些替代scheme中的任何一个,或者如果你可以build议我任何其他的解决scheme,那么我将能够提高我的查询的执行速度。 并且请不要告诉我在sqlite中启用FTS(全文search),因为我已经尝试过这样做,但我不知道确切的步骤。 非常感谢您耐心地阅读这个问题……
编辑:
嘿,所有,我取得了一些成功。 我修改我的select查询看起来像这样:
select distinct description collate nocase as description from partnumber where rowid BETWEEN 1 AND (select max(rowid) from partnumber) AND description like '%a%' order by description;
而宾果,search时间就像以前一样。 但现在的问题是,当我执行命令EXPLAIN QUERY PLAN像这样,它显示我使用B-Tree为不同的,我不想使用。
explain query plan select distinct description collate nocase as description from partnumber where rowid BETWEEN 1 AND (select max(rowid) from partnumber) AND description like '%a%' order by description;
输出:
0|0|0|SEARCH TABLE partnumber USING INTEGER PRIMARY KEY (rowid>? AND rowid<?) (~15625 rows) 0|0|0|EXECUTE SCALAR SUBQUERY 1 1|0|0|SEARCH TABLE partnumber USING INTEGER PRIMARY KEY (~1 rows) 0|0|0|USE TEMP B-TREE FOR DISTINCT
编辑:
对不起大家。 上面的方法(使用rowid进行search)在设备上花费的时间比原来的要多。 我已经尝试删除关键字的区别和顺序,但它是没有用的。 iPhone上仍然需要8-10秒。 请帮助我。
Anshul,
我知道你说:“请不要告诉我在SQLite中启用FTS(全文search),因为我已经试过这样做,但我不知道确切的步骤”,但是FTS是唯一的方法,你将得到这个执行好。 没有什么魔法可以使整个桌面扫描performance良好。 我build议阅读FTS,花时间学习,然后使用它: http : //sqlite.org/fts3.html 。