У меня есть две таблицы, t1
и виртуальная таблица FTS5 vt1
с содержанием t1
sqlite> EXPLAIN QUERY PLAN
...> SELECT Count(*) as num FROM t1 WHERE deleted = 0;
QUERY PLAN
--SEARCH TABLE t1 USING COVERING INDEX ix_t1_t1Id (deleted=?)
sqlite> SELECT Count(*) as num FROM t1 WHERE deleted = 0;
308498
Run Time: real 0.043 user 0.023668 sys 0.009005
Как видно выше, фактический запрос занимает ~ 43 мс
sqlite> EXPLAIN QUERY PLAN
...> SELECT Count(*) as num FROM vt1 WHERE vt1 MATCH 'foo';
QUERY PLAN
--SCAN TABLE vt1 VIRTUAL TABLE INDEX 131073:
sqlite> SELECT Count(*) as num FROM vt1 WHERE vt1 MATCH 'foo';
80789
Run Time: real 0.047 user 0.008021 sys 0.009640
Фактический запрос занимает ~ 47 мс. Все идет нормально. Но проблема возникает, когда я соединяю две таблицы
sqlite> EXPLAIN QUERY PLAN
...> SELECT Count(*) as num
...> FROM t1 JOIN vt1 ON t1.t1Id = vt1.t1Id
...> WHERE t1.deleted = 0 AND vt1 MATCH 'foo';
QUERY PLAN
|--SCAN TABLE vt1 VIRTUAL TABLE INDEX 0:m
--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (t1Id=?)
sqlite> SELECT Count(*) as num
...> FROM t1 JOIN vt1 ON t1.t1Id = vt1.t1Id
...> WHERE t1.deleted = 0 AND vt1 MATCH 'foo';
80789
Run Time: real 26.218 user 1.396376 sys 5.413630
Ответ правильный, но запрос занимает больше 26 секунд! Конечно, я хотел бы ускорить этот запрос на несколько порядков, но я также хотел бы понять, почему это объединение вызывает замедление.
update: так, после многих ударившись головой о стену sql, я придумал следующее - как отмечалось выше, у меня действительно есть два различных набора запросов, которые я могу сделать отдельно, например, так:
Q1: (ВЫБЕРИТЕ t1Id ОТ t1 ГДЕ…) КАК
Q2: (ВЫБЕРИТЕ t1Id ОТ vt1 ГДЕ vt1 СООТВЕТСТВУЕТ 'bar') КАК b
Затем я могу сделать следующее -
ВЫБРАТЬ СЧЕТ ( *) ОТ ГДЕ a.t1Id IN b
Конечно, на самом деле, я делаю это не отдельно, а в одном go, чтобы сделать действительно грязный SQL, но очень быстрый запрос, пару сотен мс в отличие от> 25 с
Вы можете заметить, что в моем Q2 выше я соответствовал 'bar' вместо 'foo'. Это потому, что 'bar' возвращает меньше строк, чем 'foo'. Проблема остается, когда в запросе FTS слишком много совпадений, и в этом случае сам запрос FTS является медленным, например, с 'foo', который соответствует> 80К строк.
Теперь одна интересная точка сравнения - запрос того же типа (с точки зрения пользователя) к экземпляру ElasticSearch (то есть всем строкам с 'foo' в любом месте в тексте) очень быстрый, порядка нескольких сотен мс. Я понимаю, что сравнивать SQLite с ElasticSearch может быть нечестно, но все же. (Или это справедливое сравнение?)