我有一个非常简单的查询,大约需要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
任何提示?
答案 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
中使用的每个字段创建索引