完成SQLite查询花费的时间太长

zlwx9yxi  于 2022-11-15  发布在  SQLite
关注(0)|答案(3)|浏览(323)

我有一个查询需要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);

我设法将查询时间从7秒减少到4秒,这仍然是不可接受的。我尝试了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
ffscu2ro

ffscu2ro1#

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

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

ioekq8ef2#

感谢你们所有人的回答。事实上,在我的查询中,违规者是“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秒的时间就完成了,这太棒了!

qyuhtwio

qyuhtwio3#

您的问题

从按Bond_ID分组的报价中选择Max(Date)、Bond_ID、Sell_Price;

第一:您的查询有误。不应使用保留字作为字段名称。在您的示例中是一个“Date”字段

如果您在GROUP BY中使用任何字段,还应将SELECT中的所有其他字段与任何分组函数(MIN/MAX/COUNT/等)一起使用。
对应查询应为:
按Bond_ID从报价分组中选择Max(Date)、Bond_ID;

按“Date”=Max(“Date”)的Bond_ID从报价分组中选择Bond_ID,Max(Sell_Price);

第二个

您需要为MIN/MAX/...中使用的每个字段创建索引...并在分组依据中

相关问题