3

相关问题: 如何在另一个表中选择没有匹配条目的行?

我试图使用这种方法选择行,但无法让它在 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 秒才能运行!如果我更改n.name IS E.nameton.name = E.name而让所有其他ISes 保持原样,那么查询只需要大约 400 毫秒。(表中大约有 300 万条记录event。)

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

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

4

1 回答 1

1

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

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

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

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

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

于 2013-08-13T07:21:06.090 回答