2010-04-17 88 views
7

我有两个可能的查询,都给我想要的结果集。为什么SQLite花费这么长时间来获取数据?

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

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运行。

更新

这是我所得到的,当我跑在第二的查询的解释:但是

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 

不知道这意味着什么。

+0

您如何获取数据? – dan04 2010-04-17 19:39:39

+0

使用PHP:'while($ row = $ statement-> fetch(PDO :: FETCH_OBJ))' – SQLighter 2010-04-17 19:43:05

回答

4

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

有点像快速打开大文件的方式,但是需要很长时间才能读取所有内容。

-1

使用开始事务和结束事务任何时候你写一个SQL查询。这是在这里解释以及其他许多有用的信息:

SQLite Optimization FAQ

您可以检查where子句这里的索引信息:

SQLite Query Optimizer Overview

+0

如果您不使用BEGIN/END TRANSACTION,则每条语句都会获得自己的事务。使用显式事务可以提高多条语句的效率,但OP仅执行一条语句。 – dan04 2010-04-17 19:32:18

+0

我不写。 – SQLighter 2010-04-17 19:33:16

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 (?,?,?,?) 

试试这个,看看它是否更快(并且仍然给出正确的结果)。

+0

SQLite将JOIN转换为WHERE子句。我很确定查询完成了必须做的事情。 – SQLighter 2010-04-17 19:33:04

+0

我发布的查询得到的问题是它返回重复的值。我可以用DISTINCT或临时表来解决这个问题,但这会非常缓慢,特别是当它必须处理一个巨大的结果集时。 因此,我想我可能会去周围使用一个较小的结果从featval3.IN(?,?,?,?)设置的每一行的子查询。 – SQLighter 2010-04-17 20:12:48

+1

@Derk:好的,我错过了。很难理解你的查询在做什么。我添加了DISTINCT。相关的子查询可能会很慢,因为您可能需要对表/索引进行多次扫描而不是一次扫描。 – 2010-04-17 20:17:15

相关问题