提问人:Madhukar 提问时间:9/14/2023 最后编辑:Madhukar 更新时间:9/20/2023 访问量:142
使用表变量时查询需要 10 分钟,而使用临时表时查询需要 2 秒
Query takes 10 minutes when table variables are used versus 2 seconds when temporary table is used
问:
有人写了一个使用表变量的旧查询,它在 2-3 分钟内运行。从过去 2 周开始,即使数据集大小大致相同,它也会永久运行。因此,我正在尝试优化脚本。当我用临时表替换表变量时,脚本的运行速度提高了 99.99%。究竟是什么原因?我同意表变量不适合大型数据集。但是,在这种情况下,记录计数以数千为单位。表变量和临时表都存储在 tempDB 中,那么为什么会有这种差异呢?在后端会发生什么,而表变量在 2-3 分钟内运行,现在需要花费大量时间?
DECLARE @test_table1 TABLE(/*some columns*/ );
INSERT INTO @test_table1
SELECT /*some columns*/ FROM SomeTable1
LEFT JOIN SomeTable2
LEFT JOIN SomeTable3
LEFT JOIN SomeTable4
LEFT JOIN SomeTable5
WHERE --some conditions with string and date functions
UPDATE @test_table1 SET col1 = 'xyz' WHERE SUBSTRING(col2,1,4) IN ('some values')
DECLARE @test_table2 TABLE (/*some columns*/);
WITH [cte1] AS (
SELECT /*some columns*/ FROM SomeTable1
INNER JOIN @test_table1
LEFT JOIN SomeTable2)
,[cte2] AS(
SELECT /*some columns*/ FROM SomeTable1
INNER JOIN @test_table1
LEFT JOIN SomeTable2
LEFT JOIN SomeTable3
UNION
SELECT /*some columns*/ FROM SomeTable1
INNER JOIN @test_table1
LEFT JOIN SomeTable2
LEFT JOIN SomeTable3)
,[cte3] AS(
SELECT DISTINCT /*some columns*/ FROM [cte2]
WHERE /*some simple conditions*/)
INSERT INTO @test_table2
SELECT /*some columns with string concat using stuff and xml path*/ FROM [cte3]
GROUP BY /*some columns*/
答:
“表变量保存在RAM中,使所有对它的访问都非常快 而临时表是在磁盘上物理创建的。
每当有人来问我为什么临时表实际上比表变量显示更好的性能时,我都会听到这句话的一些变化。
因此,我必须记住,即使在尝试从最简单的查询中获取数据时,引擎也会做出大量估计和假设。其中一个最重要的估计值是关于返回数据集的大小。 大多数情况下,这些表变量的不良性能是由于数据集返回了大量数据,超出了引擎愿意从 RAM 中获取的数据 并开始使用磁盘,与临时表使用的温度完全相同。
那么,为什么性能更差,性能不一样呢? 表变量应该很小,确实非常小,最重要的是,比“等效”/“默认”临时表小。 随着数据集大小的增加,引擎必须重新分配越来越多的磁盘空间,并进行越来越多的页面拆分和填充,并且由于所有这些初始假设,表变量的开销要糟糕得多。
这就是为什么我对任何尝试使用表变量或临时表的人的建议是:你有没有测试过相反的方式?
TOP 100 也可能具有误导性,这意味着只有您想显示前 100 名,但这并不意味着引擎不需要检索整个表来对一大堆数据进行排序。所有这些都是以牺牲初始预留内存空间为代价的
评论