【问题标题】:How do I avoid repeating this subquery for the IN clause?如何避免对 IN 子句重复此子查询?
【发布时间】:2011-07-25 03:12:04
【问题描述】:

我有一个 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 中做这个作为 可以 做的一个小演示,但我希望我的解决方案在尽可能少的修改的情况下尽可能地扩展。在实际情况下,数据库将有几百万行,但在我的示例中,只有 10 行带有虚拟数据。因此,可以在 MySQL 上进行很好优化的代码 绝对足够好 - 它不必专门针对 SQLite 进行优化。但正如我所说,需要的修改越少越好。

【问题讨论】:

  • 我不能代表 SQLite,但大多数体面的 RDBMS 应该能够优化这一点。对于某些产品(例如 SQL Server、postgreSQL 等),您可以使用常用的表表达式来确保文本只出现一次。
  • @Damien_The_Unbeliever:鉴于 SQLlite 是一个嵌入式数据库,一方面应该很小,并且不需要支持复杂的、长时间运行的 OLAP 类型查询,所以重量级的优化器真的不值得增加临时查询的代码和运行时间增加。

标签: sql subquery dry in-clause


【解决方案1】:

标准 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,尤其是如果你也有几个联接。

【讨论】:

  • 这是一个很好的建议,但遗憾的是 SQLite 不支持 WITH。
  • 至于性能:我要做的是通过关系表将一个表连接到自身,并过滤几个约束,然后再次执行相同的连接。约束可能会过滤掉子查询中的几百行,因此实际连接中可能不会有一百万行 =)
  • 我仍然不明白为什么您需要从 subQuery 中进行选择,然后在同一个子查询中执行 not in,无法想象这将是如何需要的。能不能把整个SQL贴出来,有兴趣看看能不能优化一下。
  • 我可能会在一段时间内发布整个代码和真实的背景信息。不过,就目前而言,我不想透露太多实际问题,因为我应该自己解决。
【解决方案2】:

您可以将 SELECT 部分放入视图中,而不是使用别名“sq”过滤视图结果

希望对你有帮助

【讨论】:

    【解决方案3】:

    您需要子查询吗?您可能可以使用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;
    

    【讨论】:

      【解决方案4】:

      总的来说,我质疑消除重复的必要性。 SQL 编译器可以看到两个子查询是相同的,并选择只执行一次,如果这看起来是最佳的。

      此外,通过在源代码中保留重复项,SQL 编译器和优化器就有机会区别对待它们。例如,SQLite 的子查询扁平化优化可能应用于一对重复项中的一个,或者以不同的方式应用于每个重复项。请参阅第 9.0 节,https://www.sqlite.org/optoverview.html 的子查询展平。

      【讨论】:

        猜你喜欢
        • 2011-05-14
        • 2016-06-28
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        • 2017-04-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多