【问题标题】:Simple SQL Server query across databases runs extremely slow R2跨数据库的简单 SQL Server 查询运行速度极慢 R2
【发布时间】:2012-10-30 13:54:01
【问题描述】:

我在本地机器上有两个数据库,连接到localhost。它们每个都有大约 200 万行。我正在执行以下非常简单的连接,并且需要一分钟多的时间才能完成。

select distinct x.patid
    from [i 3 sci study].dbo.clm_extract as x
    left join [i 3 study].dbo.claims as y on y.patid=x.patid
    where y.patid is null

当我查看执行计划时,我看到 join showplan 运算符有这样的说法

与两个表中的实际行数相比,为什么实际行数如此高?

【问题讨论】:

  • 每个表实际上有多少行?任何一个表都有关于 patid 的索引吗?
  • 每桌 200 万。我没有在 patid 上包含索引,因为 SQL Server 建议的缺失索引包含五个字段
  • 所以没有索引,您想知道为什么尝试将一侧的 200 万行匹配到另一侧的 200 万行的查询速度很慢?具有多于一列的索引有什么问题?你的意思是索引有五列,还是直接使用 INCLUDE 来带来五个额外的列?
  • 实际上是 7.61 亿行。而且估计要差得多。您的查询有一个更好的模型(尝试不存在),但如果您主要关心的是优化此查询,我会考虑仅在两侧的 patid 列上建立索引(忘记您从 Management Studio 获得的 INLCUDE 废话垃圾索引推荐)。
  • where not exists 将执行时间从 65 秒缩短到 1 秒。

标签: sql sql-server performance tsql


【解决方案1】:

LEFT JOIN 会将左侧的每一行与右侧的每一行进行匹配,然后进行过滤。假设patid 在任一表中都不是唯一的,则可能的匹配组合数量可能会非常多。

尝试以下方法:

SET NOCOUNT ON;
GO
CREATE TABLE #t1 (Id INT NOT NULL);
CREATE TABLE #t2 (Id INT NOT NULL);
GO

INSERT #t1 (Id)
VALUES (1);
GO 100

INSERT #t2 (Id)
SELECT Id FROM #t1;
GO

现在看一下左连接查询表单的执行计划:

SELECT *
FROM #t1
LEFT OUTER JOIN #t2 ON #t1.Id = #t2.Id
WHERE #t2.Id IS NULL;

查看执行计划,散列连接显示 10,000 个实际行(100 来自 #t1 x 100 来自 #t2)。这显示了使用以下任何 T-SQL 语法检查是否存在(或不存在)的优势:

SELECT #t1.Id
FROM #t1
WHERE NOT EXISTS (SELECT * FROM #t2 WHERE Id = #t1.Id);

-- #t2.Id must not contain any NULLs for this to be correct
SELECT #t1.Id
FROM #t1
WHERE Id NOT IN (SELECT #t2.Id FROM #t2);

-- Returns DISTINCT #t1 values
SELECT Id
FROM #t1
EXCEPT
SELECT Id 
FROM #t2;

检查是否存在会使引擎短路。这是由于反半连接。一旦找到第一个匹配项,它就会移动到下一个记录。更多详情,see this blog post

【讨论】:

    猜你喜欢
    • 2016-02-29
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    相关资源
    最近更新 更多