1

プログラムの奇妙な動作が発生しました。おそらく、それに光を当てることができます。

今日、私はいくつかのコードのテストを開始し、特定のクエリが非常に遅いことに気付きました (約 2 分かかりました)。

ここで選択:

select distinct table1.someName
from table1
INNER JOIN table2 ON table2.id = table1.t2_id
INNER JOIN table3 ON table1.id = table3.t1_id
INNER JOIN table4 ON Table3.id = table4.t3_id 
INNER JOIN table5 ON table5.id = table4.t5_id 
INNER JOIN table6 ON table4.id = table6.t4_id 
where t4_name = 'whatever'
and t2_name = 'moarWhatever'

and timestamp_till is null 

order by someName

つまり、結果は約120レコードです。これINNER JOINにより、チェックの量がtimestamp_till is null各レコードで約 20 レコードに削減されます。

私を最も悩ませているのは、テーブル全体table6を新しく作成されたテーブルに挿入し、名前を に変更timestamp_tillすることをテストしたことendeです。そのテーブルでは、選択は約0.1秒で行われます...

timestamp_til は SQLite3 の予約名のようなものですか? これは SQLite エンジンのバグでしょうか? それは私のせいですか?oO

編集:出力を追加EXPLAIN QUERY PLAN...

でクエリを実行すると、次のようand timestamp_till is nullになります。

0|0|4|SEARCH TABLE table5 USING COVERING INDEX sqlite_autoindex_table5 (t4_name=?) (~1 rows)
0|1|3|SEARCH TABLE table4 USING INDEX table4.fk_table4_1_idx (t5_id=?) (~10 rows)
0|2|2|SEARCH TABLE table3 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0|3|0|SEARCH TABLE table1 USING INTEGER PRIMARY KEY (rowid=?) (~1rows)
0|4|1|SEARCH TABLE table2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0|5|5|SEARCH TABLE table6 USING INDEX table6.fk_table6_ts_till (timestamp_till=?) (~2 rows)
0|0|0|USE TEMP B-TREE FOR GROUP BY
0|0|0|USE TEMP B-TREE FOR DISTINCT

高速なものは次のとおりです。

   select distinct table1.someName
    from table1
    INNER JOIN table2 ON table2.id = table1.t2_id
    INNER JOIN table3 ON table1.id = table3.t1_id
    INNER JOIN table4 ON Table3.id = table4.t3_id 
    INNER JOIN table5 ON table5.id = table4.t5_id 
    INNER JOIN table6 ON table4.id = table6.t4_id 
    where t4_name = 'whatever'
    and t2_name = 'moarWhatever'    
    order by someName

そしてその結果:

0|0|4|SEARCH TABLE table5 USING COVERING INDEX sqlite_autoindex_table5_1 (t4name=?) (~1 rows)
0|1|3|SEARCH TABLE table4 USING INDEX table4.fk_table4_1_idx (t5_id=?) (~10 rows)
0|2|2|SEARCH TABLE table3 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0|3|0|SEARCH TABLE table1 USING INTEGER PRIMARY KEY (rowid=?) (~1rows)
0|4|1|SEARCH TABLE table2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0|5|5|SEARCH TABLE table6 USING COVERING INDEX sqlite_autoindex_table6_1 (id=?) (~10 rows)
0|0|0|USE TEMP B-TREE FOR GROUP BY
0|0|0|USE TEMP B-TREE FOR DISTINCT

のコピーであるテストテーブルでtable6

0|0|4|SEARCH TABLE table5 USING COVERING INDEX sqlite_autoindex_table5_1 (name=?) (~1 rows)
0|1|3|SEARCH TABLE table4 USING INDEX table4.fk_t5_idx (t5_id=?) (~10 rows)
0|2|2|SEARCH TABLE table3 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0|3|0|SEARCH TABLE table1 USING INTEGER PRIMARY KEY (rowid=?) (~1rows)
0|4|1|SEARCH TABLE table2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0|5|5|SEARCH TABLE test USING INDEX test.fk_test__idx (id=?) (~2 rows)
0|0|0|USE TEMP B-TREE FOR GROUP BY
0|0|0|USE TEMP B-TREE FOR DISTINCT

のスクリプトを作成test

CREATE TABLE "test"(
  "id" INTEGER NOT NULL,
  "t12_id" INTEGER NOT NULL,
  "value" DECIMAL NOT NULL,
  "anfang" INTEGER NOT NULL,
  "ende" INTEGER DEFAULT NULL,
  PRIMARY KEY("id","t12_id","anfang"),
  CONSTRAINT "fk_test_t12_id"
    FOREIGN KEY("t12_id")
    REFERENCES "table12"("id"),
  CONSTRAINT "fk_test_id"
    FOREIGN KEY("id")
    REFERENCES "id_col"("id"),
  CONSTRAINT "fk_test_anfang"
    FOREIGN KEY("anfang")
    REFERENCES "ts_col"("id"),
  CONSTRAINT "fk_test_ende"
    FOREIGN KEY("ende")
    REFERENCES "ts_col"("id")
);
CREATE INDEX "test.fk_test_idx_t12_id" ON "test"("t12_id");
CREATE INDEX "test.fk_test_idx_id" ON "test"("id");
CREATE INDEX "test.fk_test_anfang" ON "test"("anfang");
CREATE INDEX "test.fk_test_ende" ON "test"("ende");

スーロン ザイ

4

1 に答える 1

2

最初の注意: SQLite はクエリで 1 つのインデックスのみを使用します。これ以上はありません (現在のバージョンで)。

したがって、SQLite が行っていることは次のとおりです。

  • 遅いクエリ: でインデックスを使用しますtimestamp_till
  • 高速クエリ (timestamp_til なし): で (自動) インデックスを使用しtable6.idます。

2 つの回避策があります。

サブクエリを使用できます:

select distinct SomeName FROM
(
   select table1.someName as "SomeName", timestamp_till
   from table1
   INNER JOIN table2 ON table2.id = table1.t2_id
   INNER JOIN table3 ON table1.id = table3.t1_id
   INNER JOIN table4 ON Table3.id = table4.t3_id 
   INNER JOIN table5 ON table5.id = table4.t5_id 
   INNER JOIN table6 ON table4.id = table6.t4_id 
   where t4_name = 'whatever'
   and t2_name = 'moarWhatever'
) Q
where timestamp_till is null 
order by SomeName;

timestamp_tillまたは、他の場所で必要ない場合は、インデックスを にドロップできます。

ジョインの順序を変更することで、速度が向上する可能性もあります。通常、最初に最小のテーブルが高速ですが、これは大きく異なる場合があります。

于 2013-02-14T18:10:58.487 に答える