为什么SQLite需要这么长时间才能获取数据?

时间:2010-04-17 19:05:14

标签: sql performance sqlite

我有两个可能的查询,都提供了我想要的结果集。

查询一个大约需要30毫秒,但需要150毫秒才能从数据库中获取数据。

SELECT 
    id
FROM 
    featurevalues as featval3
WHERE 
    featval3.feature IN (?,?,?,?) 
AND
    EXISTS
    (
        SELECT
            1
        FROM
            product_to_value,
            product_to_value as prod2,
            features,
            featurevalues
        WHERE
            product_to_value.feature = features.int
        AND
            product_to_value.value = featurevalues.id
        AND
            features.id = ? 
        AND
            featurevalues.id IN (?,?)
        AND
            product_to_value.product = prod2.product
        AND
            prod2.value = featval3.id
    )

查询2需要大约3ms - 这是我更喜欢的那个 - 但是还需要170ms来获取数据。

SELECT 
    (
        SELECT
            prod2.value
        FROM
            product_to_value,
            product_to_value as prod2,
            features,
            featurevalues
        WHERE
            product_to_value.feature = features.int
        AND
            product_to_value.value = featurevalues.id
        AND
            features.id = ? 
        AND
            featurevalues.id IN (?,?)
        AND
            product_to_value.product = prod2.product
        AND
            prod2.value = featval3.id
    ) as id
FROM 
    featurevalues as featval3
WHERE 
    featval3.feature IN (?,?,?,?) 

170ms似乎与表featval3中的行数有关。在featval3.feature IN(?,?,?,?)上使用索引后,在featval3中“保留”了151个项目。

对于缓慢取出,是否有一些明显的遗漏?据我所知,一切都被正确编入索引..我很困惑,因为第二个查询只需要花费3ms才能运行。

更新

这是我在第二个查询上运行EXPLAIN时得到的结果:

0 Trace 0 0 0 00 
1 Variable 4 1 4 00 
2 Goto 0 88 0 00 
3 OpenRead 5 6883 0 00 
4 If 6 16 0 00 
5 Integer 1 6 0 00 
6 OpenEphemeral 7 1 0 00 
7 Null 0 8 0 00 
8 MakeRecord 1 1 8 00 
9 IdxInsert 7 8 0 00 
10 MakeRecord 2 1 8 00 
11 IdxInsert 7 8 0 00 
12 MakeRecord 3 1 8 00 
13 IdxInsert 7 8 0 00 
14 MakeRecord 4 1 8 00 
15 IdxInsert 7 8 0 00 
16 Rewind 7 86 0 00 
17 Column 7 0 5 00 
18 IsNull 5 85 0 00 
19 Affinity 5 1 0 00 
20 SeekGe 5 85 5 00 
21 IdxGE 5 85 5 01 
22 Null 0 10 0 00 
23 Integer 1 11 0 00 
24 MustBeInt 11 0 0 00 
25 IfZero 11 82 0 00 
26 Variable 1 12 3 00 
27 OpenRead 2 25 0 00 
28 OpenRead 8 7005 0 00 
29 OpenRead 9 26 0 00 
30 OpenRead 10 6732 0 00 
31 OpenRead 11 6766 0 00 
32 Column 5 1 15 00 
33 IsNull 15 77 0 00 
34 Affinity 15 1 0 00 
35 SeekGe 8 77 15 00 
36 IdxGE 8 77 15 01 
37 IdxRowid 8 8 0 00 
38 Seek 2 8 0 00 
39 Column 2 0 16 00 
40 IsNull 16 76 0 00 
41 Affinity 16 1 0 00 
42 SeekGe 9 76 16 00 
43 IdxGE 9 76 16 01 
44 Column 9 1 17 00 
45 IsNull 17 75 0 00 
46 SCopy 12 18 0 00 
47 IsNull 18 75 0 00 
48 Affinity 17 2 0 00 
49 SeekGe 10 75 17 00 
50 IdxGE 10 75 17 01 
51 If 20 59 0 00 
52 Integer 1 20 0 00 
53 OpenEphemeral 13 1 0 00 
54 Null 0 21 0 00 
55 MakeRecord 13 1 21 00 
56 IdxInsert 13 21 0 00 
57 MakeRecord 14 1 21 00 
58 IdxInsert 13 21 0 00 
59 Rewind 13 74 0 00 
60 Column 13 0 19 00 
61 IsNull 19 73 0 00 
62 Affinity 19 1 0 00 
63 SeekGe 11 73 19 00 
64 IdxGE 11 73 19 01 
65 Column 9 2 21 00 
66 Column 11 0 7 00 
67 Ne 7 72 21 6a 
68 Column 8 0 22 00 
69 Move 22 10 1 00 
70 AddImm 11 -1 0 00 
71 IfZero 11 77 0 00 
72 Next 11 64 0 00 
73 Next 13 60 0 00 
74 Next 10 50 0 00 
75 Next 9 43 0 00 
76 Next 8 36 0 00 
77 Close 2 0 0 00 
78 Close 8 0 0 00 
79 Close 9 0 0 00 
80 Close 10 0 0 00 
81 Close 11 0 0 00 
82 SCopy 10 9 0 00 
83 ResultRow 9 1 0 00 
84 Next 5 21 0 00 
85 Next 7 17 0 00 
86 Close 5 0 0 00 
87 Halt 0 0 0 00 
88 Transaction 0 0 0 00 
89 VerifyCookie 0 319 0 00 
90 TableLock 0 14 0 00 
91 TableLock 0 25 0 00 
92 TableLock 0 11 0 00 
93 Goto 0 3 0 00

不确定这意味着什么。

4 个答案:

答案 0 :(得分:4)

我不确定sqlite,但是大多数数据库在执行查询时不会立即计算整个结果集。他们编译并优化查询,然后通过获取前几行开始运行它。

类似于如何快速打开大文件,但是阅读所有内容需要很长时间。

答案 1 :(得分:3)

你可能应该在这里使用JOIN,你使用相关子查询可能会减慢速度。虽然优化器通常可以使用where子句执行交叉连接,就像它是一个连接一样,并且也可以将相关子查询作为连接执行,但我不会指望SQLite能够在所有情况下执行此操作。使用JOIN重写您的查询我认为这样做:

SELECT DISTINCT prod2.value AS id
FROM product_to_value
JOIN features ON product_to_value.feature = features.int
JOIN product_to_value as prod2 ON product_to_value.product = prod2.product
JOIN featurevalues as featval3 ON prod2.value = featval3.id
JOIN featurevalues ON product_to_value.value = featurevalues.id
WHERE features.id = ?
AND featurevalues.id IN (?,?)
AND featval3.feature IN (?,?,?,?)

试试这个,看它更快(并且仍能得到正确的结果)。

答案 2 :(得分:2)

为什么不自己查看查询计划并确定答案?这是一个参考: How can I analyse a Sqlite query execution?

答案 3 :(得分:-1)

每次编写SQL查询时都使用Begin Transaction和End Transaction。这里解释了这个以及许多其他有用的信息:

SQLite Optimization FAQ

您可以在此查看where子句的索引详细信息:

SQLite Query Optimizer Overview