2

sqlite3 を使用して、共通のヘッダーを共有するさまざまな種類のレコードを保存するデータ ログ アプリがあります。

ヘッダーを 1 つの表にまとめ、各バリアントの詳細について個別の表を作成しました。

詳細テーブルの行 ID は、ヘッダー テーブルの行 ID です。ヘッダー行 ID は、(そのバリアントの) 詳細テーブルの 1 つにのみ表示されます。

1 回のクエリで複数の種類のレコードを取得したいと考えています。つまり、Sqlite でヘッダー テーブルのインデックス付き検索を実行して、作業中のレコード セットを見つけ、その ID セットを使用して、ROWID によるバリアントの詳細のクイック バイナリ フェッチを実行する必要があります。そう:

SELECT * FROM headers JOIN headers 
ON headers.id = variant1.id OR headers.id = variant2.id
WHERE some_header_condition

また

SELECT * FROM headers JOIN headers
ON headers.id IN (variant1.id, revariant2.id )
WHERE some_header_condition

これは機能しますが、JOIN 述語で OR 条件に直面すると、sqlite3 は行 ID 外部キーによって適切なレコードをフェッチするだけでなく、詳細テーブル variant1 および variant2 の完全なテーブル スキャンを実行します。

何かのようなもの:

0     0              2     SCAN TABLE variant2 (~5900 rows)
0     1              1     SCAN TABLE variant1 (~26588 rows)
0     2              0     SEARCH TABLE headers USING INTEGER PRIMARY KEY (rowid=?) (~2 rows)
0     0              0     EXECUTE LIST SUBQUERY 1

次のようなトリックを行うことで、バイナリ検索を強制できます。

SELECT header.f1, variant1.f, NULL FROM header JOIN header.id = variant1.id ...
UNION ALL
SELECT header.f1, NULL, variant2.f FROM header JOIN header.id = variant2.id ...

ただし、ヘッダー テーブルは 2 回アクセスされます。

また、header.id(s) を一時テーブルに選択し、それを使用して ID を使用して詳細を取得することも想像できます。

または...混乱全体を非正規化することもできます。

しかし、これらの回避策はすべて非常に不便です。私の質問は、これらのバリアントをテーブル スキャンなしで一度に取得できる素敵な JOIN クエリはありますか?

4

1 に答える 1

2

外部結合を使用してみてください。

SELECT *
FROM headers
  LEFT JOIN variant1 ON headers.id = variant1.id
  LEFT JOIN variant2 ON headers.id = variant2.id
WHERE headers...

次のような計画になります。

sele  order  from  deta
----  -----  ----  ----
0     0      0     SEARCH TABLE headers USING INTEGER PRIMARY KEY (rowid>? AND rowid<?) (~31250 rows)
0     1      1     SEARCH TABLE variant1 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0     2      2     SEARCH TABLE variant2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
于 2012-10-17T18:04:00.513 に答える