SQLite查询计划

时间:2016-01-13 15:43:30

标签: sqlite dbi

有没有办法操纵在SQLite中生成的查询计划?

我试着解释一下我的问题:

我有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");

index_term中约有600.000个条目,index_posting中约为4百万个,published_files表中为300.000个。

现在,当我想在index_posting中找到引用某些术语的唯一doc_ids的数量时,我使用以下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=?)

当我想以只包含index_posting的doc_id的方式过滤计数时,如果存在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始终使用正确的查询计划?

TIA

1 个答案:

答案 0 :(得分:1)

ANALYZE不是解决方法;它应该被使用。

您可以使用CROSS JOIN强制执行嵌套循环的特定顺序,或使用INDEXED BY强制使用某个索引。 但是,您要求“正确的查询计划”,这可能与这些机制强制执行的计划不同。