SQL 优化器/执行计划 - 重复子查询

Posted

技术标签:

【中文标题】SQL 优化器/执行计划 - 重复子查询【英文标题】:SQL Optimizer / Execution Plan - Repeated Subqueries 【发布时间】:2013-03-25 15:03:59 【问题描述】:

注意:我目前正在一个 sqlite3 数据库上运行我的查询,但欢迎来自任何其他 DBMS 专业知识的回答......

我想知道查询优化器是否会尝试识别重复的查询/子查询,如果是,则只运行一次。

这是我的示例查询:

SELECT *
  FROM table1 AS t1
 WHERE t1.fk_id =
 (
    SELECT t2.fk_id
      FROM table2 AS t2
     WHERE t2.id = 1111
 )
 OR t1.fk_id =
 (
    SELECT local_id 
      FROM ID_MAP
     WHERE remote_id =
     (
        SELECT t2.fk_id
          FROM table2 AS t2
         WHERE t2.id = 1111
     )
 );

将嵌套查询

SELECT t2.fk_id
  FROM table2 AS t2
 WHERE t2.id = 1111

只运行一次(并缓存其结果以供进一步访问)?

在这个例子中没什么大不了的,因为它是一个只执行两次的简单查询,但是我需要它运行 在我的实际程序中(它抓取所有子记录(表 1) 关联到由外键绑定的父记录 (table2)。它还检查一个 id 映射表以确保它查询 对于本地生成的 id 以及真实/更新/新密钥)。

非常感谢您对此提供的任何帮助,谢谢。

【问题讨论】:

【参考方案1】:

SQLite 有一个非常简单的查询优化器,甚至不会尝试检测相同的子查询:

> create table t(x);
> explain query plan
  select * from t
  where x in (select x from t) or
        x in (select x from t);
0|0|0|SCAN TABLE t (~500000 rows)
0|0|0|EXECUTE LIST SUBQUERY 1
1|0|0|SCAN TABLE t (~1000000 rows)
0|0|0|EXECUTE LIST SUBQUERY 2
2|0|0|SCAN TABLE t (~1000000 rows)

这同样适用于 CTE 和视图;如果性能确实很重要,最好的办法是为子查询的结果创建一个临时表。

【讨论】:

"explain query plan" 我什至不知道 DBMS 有这样的命令,太棒了。我遇到的问题的核心是将本地生成的临时 ID 与更新到远程数据库后发回的“真实”临时 ID 同步。它的父/子外键关系变得棘手。父记录和子记录都可以在本地生成,从而获得临时 ID,并且我使用 ID_MAP 表进行跟踪。我试图避免应用程序级锁定,但我不确定最好的选择是使用事务(开始/提交)还是嵌套查询来击败潜在的竞争条件? 为了防止竞争,使用事务。 (如果没有显式事务,每个命令将被包装到一个自动事务中,因此围绕多个命令的显式事务甚至可以减少事务开销。)但是,应用程序级锁可能比SQLite's locking scheme 更有效。无论如何,在遇到实际性能问题之前不要费心优化。 好的。嵌套查询是自动触发的,还是被分解成单独的语句(反过来又被包装成单独的事务)?我问 b/c 我不确定天气是否暗示嵌套查询不会自动触发(因此防止比赛)?感谢所有的帮助。 ... 另外,我正在远离应用程序级锁 b/c 涉及两个独立的进程,它们通过一个作为表实现的请求队列进行通信。我开始编写锁代码,意识到我刚刚在锁表上遇到了竞争条件,在前进程和后台进程之间,所以决定解决它所在的问题(此外,锁检查开始到处弹出) .我仍然希望我可以使用它们。 自动事务处理整个语句(包括任何子查询,以及在触发器中完成的任何事情)。【参考方案2】:

当您要求其他数据库提供见解时......

在 Oracle DBMS 中,任何独立的子查询都只会执行一次。

SELECT t2.fk_id
  FROM table2 AS t2
 WHERE t2.id = 1111  -- The result will be the same for any row in t1.

当然,依赖子查询需要重复执行。

依赖子查询示例:

SELECT t2.fk_id
  FROM table2 AS t2
 WHERE t2.id = t1.t2_id  -- t1.t2_id will have different values for different rows in t1.

【讨论】:

有趣的概念,独立/独立的子查询。完全有道理,只是在写这个问题时我没有意识到。谢谢!

以上是关于SQL 优化器/执行计划 - 重复子查询的主要内容,如果未能解决你的问题,请参考以下文章

Mysql学会查看sql的执行计划

SQL Server查询优化器执行计划“语句提前终止的原因:超时”

Mysql 学习总结(87)—— Mysql 执行计划(Explain)再总结

MySQL 优化sql explain执行计划详解

SQL Server执行计划

MSSQLSERVER执行计划详解