在SQL Server中,此查询的运行速度非常快,不到一秒:
SELECT T1.id
FROM first AS T1
WHERE T1.id = 21
这个查询也运行得非常快,不到一秒,尽管它有5300万条记录,但只有大约6条ID为21的记录:
SELECT TOP 1 T2.value
FROM second AS T2 WITH(INDEX(IX_second))
WHERE T2.id = 21
AND T2.b = 1
AND T2.c = 0
AND T2.d = 0
AND T2.e = 0
ORDER BY T2.id, T2.b, T2.c, T2.d, T2.e, T2.timestamp DESC
但是,在这个查询中,我将内部SELECT
中的21替换为T1.id,速度非常非常慢,超过80秒:
SELECT T1.id, T3.value
FROM first AS T1
JOIN second AS T3 ON T3.id IN (SELECT TOP 1 T2.id
FROM second AS T2 WITH(INDEX(IX_second))
WHERE T2.id = T1.id
AND T2.b = 1
AND T2.c = 0
AND T2.d = 0
AND T2.e = 0
ORDER BY T2.id, T2.b, T2.c, T2.d, T2.e, T2.timestamp DESC)
WHERE T1.id = 21
为什么这个查询要花这么长的时间,我如何使它更快?
编辑:以下是计划,更改了一些表名和字段名以保护无辜:)brentozar.com/pastetheplan/?id=rJYBSfwws
3条答案
按热度按时间mrfwxfqh1#
这看起来像是可以使用
CROSS APPLY
的情况。这允许使用TOP 1
和ORDER BY
,但会避免对second
表的双重引用。试试看:
如果
IX_second
是second(id)
上的索引,则SQL Server查询优化器可能会选择该索引,而不需要索引提示。只是为了检查:你确定你指的是
T2.id = T1.id
而不是T2.first_id = T1.id
之类的东西吗?还有一点要注意:由于
T2.id, T2.b, T2.c, T2.d, T2.e
在CROSS APPLY
结果中都是固定的,因此可以将它们从ORDER BY
子句中删除。ADDENDUM:根据您发布的执行计划中的查询,上面的内容相当于:
n3schb8v2#
这一切都取决于DBMS计算数据的方式。但在这种情况下,53M将被处理(T1 X T3)次。每次都将进行排序、反转、查询,如果索引不是用值(b,c,d,e...)构建的,还可能与源表进行一些连接。
我不明白您的查询逻辑。为什么不使用一个连接...
这看起来与上述结果相同。
2jcobegt3#
在
IN()
语句中使用子查询在语法上是可以的,但我不推荐这样做,因为管理表之间的JOIN的速度较慢。正如其他人所建议的,使用一个 * 临时表 *。在我看来,即使是CTE()也至少是一个更干净的代码版本,更容易理解。您还需要研究您的执行计划。
我还没有测试过这个,但是可以尝试这样做:
我敢打赌这会更快,但可能没有你想象的那么快。
同样,您需要研究每个案例的执行计划,确定确切的瓶颈,并在必要的地方放置
INDEXes
。