简单的SQLite查询需要很长时间才能完成

时间:2013-09-19 11:37:56

标签: android sqlite

我有一个非常简单的查询,大约需要4秒钟才能完成:

SELECT MAX(Date), Bond_Id, Sell_Price FROM Quotes GROUP BY Bond_Id;

该表格也很简单,只有31K条记录。这是架构:

CREATE TABLE Quotes (
    _id         INTEGER PRIMARY KEY AUTOINCREMENT, 
    Bond_Id     INTEGER NOT NULL, 
    Date        TEXT NOT NULL, 
    Buy_Yield   REAL NOT NULL, 
    Sell_Yield  REAL NOT NULL, 
    Buy_Price   REAL NOT NULL, 
    Sell_Price  REAL NOT NULL, 
    Base_Price  REAL NOT NULL, 
    FOREIGN KEY (Bond_Id) REFERENCES Bonds(_id));

CREATE INDEX QuotesNdx ON Quotes(Bond_Id);

我研究了SQLite文档并设法将查询时间从7s减少到4s,这仍然是不可接受的。我已经开了好几天了,没有运气。我已经尝试过ANALYZE,一些额外的复合索引,并试图删除外键。什么都没有。

这是EXPLAIN输出:

0 Trace 0 0 0 explain select max(date),bond_id,sell_price from quotes group by bond_id; 00 
1 Noop 0 0 0  00 
2 Integer 0 6 0  00 
3 Integer 0 5 0  00 
4 Goto 0 20 0  00 
5 Integer 1 6 0  00 
6 Return 0 0 0  00 
7 IfPos 5 9 0  00 
8 Return 0 0 0  00 
9 AggFinal 1 1 0 max(1) 00 
10 SCopy 1 9 0  00 
11 SCopy 2 10 0  00 
12 SCopy 3 11 0  00 
13 ResultRow 9 3 0  00 
14 Return 0 0 0  00 
15 Null 0 2 0  00 
16 Null 0 3 0  00 
17 Null 0 4 0  00 
18 Null 0 1 0  00 
19 Return 0 0 0  00 
20 Gosub 0 15 0  00 
21 Goto 0 48 0  00 
22 SetNumColumns 0 7 0  00 
23 OpenRead 0 6 0  00 
24 SetNumColumns 0 2 0  00 
25 OpenRead 2 7 0 keyinfo(1,BINARY) 00 
26 Rewind 2 44 13 0 00 
27 Noop 2 -7 13 0 01 
28 IdxRowid 2 16 0  00 
29 MoveGe 0 0 16  00 
30 Column 2 0 8  00 
31 Eq 7 36 8 collseq(BINARY) 10 
32 Move 8 7 0  00 
33 Gosub 0 7 0  00 
34 IfPos 6 47 0  00 
35 Gosub 0 15 0  00 
36 Column 0 2 17  00 
37 CollSeq 0 0 0 collseq(BINARY) 00 
38 AggStep 0 17 1 max(1) 01 
39 SCopy 7 2 0  00 
40 Column 0 6 3  00 
41 RealAffinity 3 0 0  00 
42 Integer 1 5 0  00 
43 Next 2 27 0  00 
44 Close 0 0 0  00 
45 Close 2 0 0  00 
46 Gosub 0 7 0  00 
47 Halt 0 0 0  00 
48 Transaction 0 0 0  00 
49 VerifyCookie 0 9 0  00 
50 TableLock 0 6 0 Quotes 00 
51 Goto 0 22 0  00 

任何提示?

3 个答案:

答案 0 :(得分:2)

可以通过创建covering index来优化此特定查询;列必须按照它们用于查找的顺序:

CREATE INDEX whatever ON Quotes(Bond_ID, Date, Sell_Price);

答案 1 :(得分:0)

谢谢大家的回答。实际上,我的查询中的罪犯是“GROUP BY”。我通过阅读SQLite的SELECT(http://sqlite.org/lang_select.html)文档中的这一特定段落找到了解决方案:

  

“如果SELECT语句是带有GROUP BY子句的聚合查询,则为数据集的每一行计算作为GROUP BY子句一部分指定的每个表达式。然后将每一行分配给一个”组“基于结果;评估GROUP BY表达式的结果相同的行被分配给同一组。为了对行进行分组,NULL值被认为是相等的。通常的规则用于选择与之对应的归类序列比较文本值在计算GROUP BY子句中的表达式时适用.GROUP BY子句中的表达式不必是结果中出现的表达式.GROUP BY子句中的表达式可能不是聚合表达式。

因此,解决方案是创建一个包含(Date,Bond_Id)的复合索引,并用以下内容替换我的查询:

SELECT Date, Bond_Id, Sell_Price FROM Quotes
   WHERE Bond_Id=Bonds._id
   AND Date=(SELECT MAX(Date) FROM Quotes);

现在这个查询完成时间不到1秒,这太棒了!

答案 2 :(得分:-1)

您的查询

  

SELECT MAX(Date),Bond_Id,Sell_Price FROM Quotes GROUP BY Bond_Id;

<强>第一: 您的查询不正确。您不应将保留字用作字段名称。在你的情况下是一个字段“日期”

如果你在GROUP BY中使用任何字段,你也应该使用SELECT中的所有其他字段和任何分组函数(MIN / MAX / COUNT / etc ..)

Corrent查询应该是:

SELECT MAX(Date),Bond_Id FROM Quotes GROUP BY Bond_Id;

SELECT Bond_Id,MAX(Sell_Price)FROM Quotes GROUP BY Bond_Id HAVING“Date”= MAX(“Date”);

<强> SECOND

您需要为MIN / MAX / ...和GROUP BY

中使用的每个字段创建索引
相关问题