2016-01-13 5 views
0

Есть ли способ манипулировать планом запроса, сгенерированным в SQLite?SQLite Query plan

I «л попытаться объяснить мою проблему:

У меня есть 3 таблицы:

CREATE TABLE "index_term" (
    "id" INT, 
    "term" VARCHAR(255) NOT NULL, 
    PRIMARY KEY("id"), 
    UNIQUE("term")); 

CREATE TABLE "index_posting" (
    "doc_id" INT NOT NULL, 
    "term_id" INT NOT NULL, 
    PRIMARY KEY("doc_id", "field_id", "term_id"),, 
    CONSTRAINT "index_posting_doc_id_fkey" FOREIGN KEY ("doc_id") 
    REFERENCES "document"("doc_id") ON DELETE CASCADE, 
    CONSTRAINT "index_posting_term_id_fkey" FOREIGN KEY ("term_id") 
    REFERENCES "index_term"("id") ON DELETE CASCADE);; 
CREATE INDEX "index_posting_term_id_idx" ON "index_posting"("term_id"); 

CREATE TABLE "published_files" (
    "doc_id" INTEGER NOT NULL,, 
    "uri_id" INTEGER, 
    "user_id" INTEGER NOT NULL, 
    "status" INTEGER NOT NULL, 
    "title" VARCHAR(1024), 
    PRIMARY KEY("uri_id")); 
CREATE INDEX "published_files_doc_id_idx" ON "published_files"("doc_id"); 

около 600,000 записей в index_term, около 4 миллионов в index_posting и 300.000 в таблице published_files.

Теперь, когда я хочу найти количество уникальных doc_ids в index_posting, которые ссылаются на некоторые термины, я использую следующий SQL.

select count(distinct index_posting.doc_id) from index_term, index_posting 
    where 
    index_posting.term_id = index_term.id and index_term.term like '%test%' 

Результат будет показан в течение разумного периода времени (0.3 секунд). Просить Объяснить план запроса возвращает

0|0|0|SCAN TABLE index_term 
0|1|1|SEARCH TABLE index_posting USING INDEX index_posting_term_id_idx (term_id=?) 

Когда я хочу, чтобы отфильтровать количество в том, что она включает в себя только doc_ids из index_posting, если существует запись published_files:

select count(distinct index_posting.doc_id) from index_term, index_posting, 
    published_files where 
    index_posting.term_id = index_term.id and index_posting.doc_id = published_files.doc_id and index_term.term like '%test%' 

Запрос занимает почти 10 раз длинный. Просить Объяснить план запроса возвращает

0|0|1|SCAN TABLE index_posting 
0|1|0|SEARCH TABLE index_term USING INDEX sqlite_autoindex_index_term_1 (id=?) 
0|2|2|SEARCH TABLE published_files AS pf USING COVERING INDEX published_files_doc_id_idx (doc_id=?) 

Так, насколько я понимаю, SQLITE изменил здесь свой план запроса делает полное сканирование таблицы в index_posting и поиск в index_term вместо наоборот.

В качестве обходного пути я сделал сделать

analyze index_posting; 
analyze index_term; 
analyze published_files; 

и теперь кажется правильным,

0|0|0|SCAN TABLE index_term 
0|1|1|SEARCH TABLE index_posting USING INDEX index_posting_term_id_idx (term_id=?) 
0|2|2|SEARCH TABLE published_files USING COVERING INDEX published_files_doc_id_idx (doc_id=?) 

но мой вопрос - есть ли способ заставить SQLITE всегда использовать правильный план запроса ?

ТИА

ответ

1

ANALYZE не обходной путь; он должен использоваться.

Вы можете использовать CROSS JOIN для принудительного исполнения определенного порядка вложенных циклов или использовать INDEXED BY для принудительного использования определенного индекса. Однако вы попросили «правильный план запроса», который может быть не таким, как тот, который применяется этими механизмами.