使用OR术语在sqlite / JOIN中选择高效的变体记录

时间:2012-10-17 17:45:29

标签: sql join sqlite

我有一个使用sqlite3的数据记录应用程序来存储共享公共标题的不同类型的记录。

我将标题放在一个表中,并为每个变体的详细信息创建了单独的表。

详细信息表中的rowid是标头表的rowid。标题rowid仅显示在其中一个详细信息表中(对于该变体)。

我想在一个查询中获取多种类型的记录。 也就是说,我希望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会对详细信息表variant1和variant2进行全表扫描,而不是仅通过rowid外键获取相应的记录。

类似的东西:

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 ...

然后,头表被访问两次。

我还可以想象选择header.id(s)到临时表并使用它来使用ID IN来获取详细信息。

或者......我可以将整个混乱程序归一化。

但所有这些变通方法都非常不方便。所以我的问题是,是否有一个很好的JOIN查询可以一次性获取这些变量而没有表扫描?

1 个答案:

答案 0 :(得分: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)