2010-04-17 90 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

相關問題