当存在NULL时,性能选择与另一个表中的条目不匹配的行

时间:2013-08-13 04:27:50

标签: sql sqlite

相关问题: How to select rows with no matching entry in another table?

我试图使用此方法选择行,但无法在SQLite中使用它。经过一番争吵之后,我发现原因可能是某些字段中存在NULL值。果然,我是对的,当我在下面的查询中将=更改为IS时,事情开始按预期运行:

CREATE TEMP TABLE newEvent(id INTEGER,t INTEGER,name,extra,extra2,extra3);
INSERT INTO newEvent(id,t,name,extra,extra2,extra3) VALUES
                           (0, 1376351146, 'TEST', NULL, NULL, NULL),
                           (0, 1376348867, 'OLD', NULL, NULL,NULL);
SELECT n.id,n.t,n.name,n.extra,n.extra2,n.extra3 FROM newEvent n 
       LEFT JOIN event E ON n.t = E.t AND n.name IS E.name
                                      AND n.extra IS E.extra;
                                      AND n.extra2 IS E.extra2;
                                      AND n.extra3 IS E.extra3
       WHERE E.id IS NULL;
DROP TABLE newEvent;

在上面的示例中,表event中存在name='OLD'的现有记录。 newEvent表的定义与原始event表的定义相同。

然而,我注意到一个很大的问题:我的查询现在花了将近30秒的时间来运行!如果我将{em>仅 n.name IS E.name更改为n.name = E.name,但将所有其他IS保留为原样,那么查询只需要大约400毫秒。 (表event中有大约300万条记录。)

为什么性能差异很大?事实证明,我实际上可以使用=代替IS来进行name比较,因为它永远不会为空,但如果它曾经是NULL,那么它似乎会破坏。相反,我担心在某些时候查询可能会开始运行缓慢,因为我不明白它是什么name使得相等查询运行得更快。我的猜测是,也许SQLite以某种方式知道额外字段中存在空值并且能够进行优化,但我想要比疯狂猜测更坚定的东西。

据我所知,IS只是=,附加条件是它会将NULL比较视为空字符串(假设没有实际的空字符串可比较) )。那么为什么在名称字段上使用=的速度要快75倍,但对额外字段的性能没有影响???

1 个答案:

答案 0 :(得分:1)

在连接中,SQLite可以使用索引查找优化=,但不能IS。 此外,在单个查询中,每个表不可能使用多个索引。

因此,要么您没有包含nameextra *的多列索引,要么附加列的选择性不够高。

您可以使用compound SELECT尝试完全不同的查询:

SELECT t, name, extra, extra2, extra3 FROM newEvent
EXCEPT
SELECT t, name, extra, extra2, extra3 FROM event

但是,这不允许您获得不合适的列(例如您的id)。