Почему SQLite занимает так много времени, чтобы получить данные? - PullRequest
7 голосов
/ 17 апреля 2010

У меня есть два возможных запроса, оба дают желаемый набор результатов.

Запрос один занимает около 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
    )

Запрос два занимает около 3 мс - это тот, который я поэтому предпочитаю, но также и 170 мс для извлечения данных.

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

Кажется, 170 мс связаны с количеством строк в таблице featval3. После использования индекса для featval3.feature IN (?,?,?,?) 151 элемент "остается" в featval3.

Есть что-то очевидное, чего мне не хватает в отношении медленной загрузки? Насколько я знаю, все правильно проиндексировано ... Я запутался, потому что второй запрос занимает всего 3 мсек.

Обновление

Вот что я получаю, когда запускаю 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 ]

4 голосов
/ 17 апреля 2010

Я не уверен насчет sqlite, но большинство баз данных сразу не вычисляют весь набор результатов при выполнении запроса. Они компилируют и оптимизируют запрос, а затем начинают его, извлекая первые несколько строк.

Вроде как быстрое открытие большого файла, но тогда для прочтения всего содержимого требуется много времени.

3 голосов
/ 17 апреля 2010

Вы, вероятно, должны использовать здесь 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 голосов
/ 17 апреля 2010

Почему бы не взглянуть на план запроса и самостоятельно определить ответ? Вот ссылка: Как я могу проанализировать выполнение запроса Sqlite?

0 голосов
/ 17 апреля 2010

Используйте Begin Transaction и End Transaction каждый раз, когда вы пишете SQL-запрос. Это объясняется здесь, плюс много другой полезной информации:

Часто задаваемые вопросы по оптимизации SQLite

Вы можете проверить детали индексации здесь, где:

Обзор оптимизатора запросов SQLite

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...