У меня есть два возможных запроса, оба предоставления набора результатов, который я хочу.
Запросите каждый берет приблизительно 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 В (????), 151 объект "остается" в featval3.
Действительно ли там что-то очевидно, что я отсутствую относительно медленной выборки? Насколько я знаю, что все правильно индексируется.. Я смущен, потому что второй запрос только берет сверкающие 3 мс для выполнения.
Обновление
Это - то, что я получаю, когда я выполняю ОБЪЯСНЕНИЕ на втором запросе:
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
Не уверенный, что это означает как бы то ни было.
Вам, вероятно, следует использовать здесь СОЕДИНЕНИЯ, а использование коррелированных подзапросов вполне может замедлить работу . Хотя это правда, что часто оптимизатор может выполнить перекрестное соединение с предложением 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 (?,?,?,?)
Попробуйте это и убедитесь, что это быстрее (и все же дает правильный результат).
Используйте "Начать транзакцию" и "Завершить транзакцию" каждый раз, когда вы пишете запрос sql. Это объясняется здесь, а также много другой полезной информации:
Часто задаваемые вопросы по оптимизации SQLite
Вы можете проверить детали индексации в предложении where здесь:
Я не уверен насчет sqlite, но большинство баз данных не вычисляют все набор результатов сразу после выполнения запроса. Они компилируют и оптимизируют запрос, а затем начинают его выполнение, извлекая первые несколько строк.
Что-то вроде того, как быстро открыть большой файл, но потом требуется много времени, чтобы прочитать все его содержимое.
Почему бы не взглянуть на план запроса и не определить ответ самостоятельно? Вот ссылка: Как я могу проанализировать выполнение запроса Sqlite?