我有一个 SQL 脚本(当前针对 SQLite 运行,但它可能应该适用于任何数据库引擎),它两次使用相同的子查询,并且由于它可能会获取大量记录(该表有几百万行)我只想调用一次。
查询的缩短伪版本如下所示:
SELECT * FROM
([the subquery, returns a column of ids]) AS sq
[a couple of joins, that fetches things from other tables based on the ids]
WHERE thisorthat NOT IN ([the subquery again])
我尝试以各种方式使用名称(
sq
)(带/不带括号,带/不命名 sq 列等),但无济于事。
我真的有重复这个子查询吗?
澄清: 我正在 python 和 sqlite 中执行此操作,作为 can 可以做什么的小演示,但我希望我的解决方案能够在尽可能少的修改的情况下尽可能地扩展。在真实情况下,数据库将有几百万行,但在我的示例中只有 10 行包含虚拟数据。因此,能够在例如 MySQL 上进行良好优化的代码绝对足够好 - 它不必专门针对 SQLite 进行优化。但正如我所说,需要的修改越少越好。
标准 SQL 中有一个
WITH
子句,但是,我不知道 SQLlite 是否支持它 - 当然值得一试:
WITH mySubQuery AS
(
[the subquery code]
)
SELECT * FROM
mySubQuery AS sq
[a couple of joins, that fetches things from other tables based on the ids]
WHERE thisorthat NOT IN (mySubQuery)
也就是说,对于任何超过几千行的数据集,你在这里所做的可能会非常慢,所以如果可能的话,我会尝试对其进行重新建模 -
NOT IN
一般情况下应该避免,特别是如果你也这样做的话有几个加入。
您需要子查询吗?您可能可以使用
OUTER JOIN
重写,例如像这样的东西:
SELECT *
FROM [the subquery's FROM clause] AS sq
RIGHT OUTER JOIN [a couple of tables based on the ids]
ON thisorthat = sq.[a column of ids]
WHERE sq.[a column of ids] IS NULL;
总的来说,我质疑消除重复的必要性。 SQL 编译器可以看到两个子查询是相同的,如果这看起来是最佳的,则选择只执行一次。
此外,通过在源代码中保留重复项,SQL 编译器和优化器有机会以不同的方式对待它们。例如,SQLite 的子查询扁平化优化可能应用于一对重复项中的一个,或者以不同的方式应用于每个重复项。请参阅第 9.0 节,子查询扁平化 https://www.sqlite.org/optoverview.html。
您可以将 SELECT 部分放入视图中,然后使用别名“sq”过滤视图结果