sql - 为什么 IF(查询)需要一个多小时,而查询只需要不到一秒?

标签 sql sql-server

我有以下 SQL:

 IF EXISTS
 (
    SELECT
        1
    FROM
        SomeTable T1
    WHERE
        SomeField = 1
    AND SomeOtherField = 1
    AND NOT EXISTS(SELECT 1 FROM SomeOtherTable T2 WHERE T2.KeyField = T1.KeyField)
)
    RAISERROR ('Blech.', 16, 1)

SomeTable 表大约有 200,000 行,SomeOtherTable 表大约有 200,000 行。

如果我执行内部 SQL(SELECT),它会在亚秒内执行,不会返回任何行。但是,如果我执行整个脚本 (IF...RAISERROR),则需要一个多小时。 为什么?

现在,显然执行计划有所不同 - 我可以在企业管理器中看到这一点 - 但再说一次,为什么

我可能可以做类似 SELECT @num = COUNT(*) WHERE ...然后 IF @num > 0 RAISERROR 但是...我认为那是有点没有捕获重点。如果您知道错误存在,您只能围绕错误进行编码(对我来说它确实看起来像错误)。

<小时/>

编辑:

我应该提到,我已经尝试按照 @Bohemian 的答案将查询重新调整为 OUTER JOIN,但这对执行时间没有影响。

<小时/>

编辑 2:

我已附上内部 SELECT 语句的查询计划:

Query Plan - inner SELECT statement

...以及整个 IF...RAISERROR block 的查询计划:

Query Plan - whole IF statement

显然,这些显示了真实的表/字段名称,但除此之外,查询与上面所示完全相同。

最佳答案

IF 不会神奇地关闭优化或破坏计划。优化器刚刚注意到 EXISTS 最多只需要一行(如 TOP 1)。这称为“行目标”,通常在您进行分页时发生。但也有 EXISTSINNOT IN 等。

我的猜测:如果您将 TOP 1 写入原始查询,您会得到相同(错误)的计划。

优化器在这里尝试变得聪明,只使用更便宜的操作生成第一行。不幸的是,它错误地估计了基数。它猜测查询将产生大量行,尽管实际上它不会产生任何行。如果它估计正确,您只会得到一个更有效的计划,否则它根本不会进行转换。

我建议采取以下步骤:

  1. 通过检查索引和统计数据来修正计划
  2. 如果这没有帮助,请将查询更改为 IF (SELECT COUNT(*) FROM ...) > 0 这将给出原始计划,因为优化器没有行目标.

关于sql - 为什么 IF(查询)需要一个多小时,而查询只需要不到一秒?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15634733/

相关文章:

mysql - 仅包含唯一字符串的专用 SQL 表

sql-server - SQL Server中主键(簇)和簇唯一索引的区别

sql - 有没有办法保证 MySQL 中的非阻塞读取?

php - 插入自动增量字段的最佳方法? (PHP/MySQL)

c# - 如何将数据作为序列化对象插入数据库

SQL Server 数据库更改工作流最佳实践

sql-server - SQL Server : sp_MSforeachdb into single result set

java - 搜索功能的 SQL 查询

php - 创建一个 View ,获取排名、用户名和用户记录数

sql - 外键到非主键