子树成本和性能时间之间的 SQL 关系

9 performance database-design sql-server optimization performance-tuning

“SQL 最终子树成本”和“查询时间性能”之间的一般关系是什么?

示例:当优化查询并且它从子树成本 0.2 到 0.1 时,这是否意味着查询时间将快两倍?我在查询中没有看到这种情况。

我们有一个服务器,即使使用“设置统计时间”和“DBCC DROPCLEANBUFFERS”也无法真正衡量查询性能。服务器、事务、程序、后台项目中有不同的进程在进行。

谢谢,

Joe*_*ish 14

子树成本表示计划的估计成本。在调查查询优化器为什么选择一种计划而不是另一种计划时,它会很有用。例如,您可能会看到一个带有散列连接的计划,并认为循环连接会是一个更有效的选择。添加查询提示以强制循环连接并比较子树成本有助于确定 SQL Server 选择散列连接的原因。

由于许多原因,计划的估计成本通常与查询的“性能时间”不匹配,包括硬件差异、其他进程的阻塞、整体服务器工作负载、模型限制以及基于不完善信息的假设。此外,0.1 和 0.2 的子树成本实际上根本没有有意义的差异。如果您的查询相对于其余工作负载的相对成本较低,但该查询运行了很长时间,则表明查询优化器做出了不正确的假设或推论。这些类型问题的根本原因通常归结为基数估计。另一方面,有时相对昂贵的查询会运行很长时间。查看计划中估计需要很长时间的部分可以提供有用的线索,说明为什么查询要运行很长时间。但是,一些查询调谐器会告诉您根本不要查看估计成本。

下面是一些示例查询,只是为了表明估计成本和运行时间之间可能存在极大差异。我正在 SQL Server 2017 上进行测试,但可以在所有版本中提供类似的演示。首先,我将 100k 个连续整数放入堆中:

CREATE TABLE dbo.OptimizerUnits (ID BIGINT NOT NULL);

INSERT INTO dbo.OptimizerUnits WITH (TABLOCK)
SELECT TOP (100000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)

考虑以下查询:

SELECT ID
FROM dbo.OptimizerUnits 
WHERE 
(ID % 10) % 101  = 10
Run Code Online (Sandbox Code Playgroud)

人类可以查看该查询并推断它不会返回任何行,但优化器目前没有内置这种逻辑。相反,它猜测将返回大约 990 行。这使以下查询的总估计成本为 79590.1 单位:

WITH OptimizerUnitsCTE (ID) AS 
(
    SELECT ID
    FROM dbo.OptimizerUnits 
    WHERE 
    (ID % 10) % 101  = 10
)
SELECT TOP (100) t1.ID, t2.ID, t3.ID
FROM OptimizerUnitsCTE t1
CROSS JOIN OptimizerUnitsCTE t2
CROSS JOIN OptimizerUnitsCTE t3
ORDER BY t1.ID + t2.ID + t3.ID DESC;
Run Code Online (Sandbox Code Playgroud)

但是,查询在我的机器上运行不到 50 毫秒。

现在让我们转向另一个方向。考虑以下查询:

SELECT ID
FROM dbo.OptimizerUnits 
WHERE 
(ID % 10) % 101  = 1
AND (ID % 10) % 102  = 1
AND (ID % 10) % 103  = 1
AND (ID % 10) % 104  = 1
Run Code Online (Sandbox Code Playgroud)

再一次,人类可以推断出上述查询将准确返回 10000 行。查询优化器不知道这一点,它猜测查询将仅返回 16.7439 行。这导致以下查询的估计成本为 1.45306 个优化器单元:

WITH OptimizerUnitsCTE (ID) AS 
(
    SELECT ID
    FROM dbo.OptimizerUnits 
    WHERE 
    (ID % 10) % 101  = 1
    AND (ID % 10) % 102  = 1
    AND (ID % 10) % 103  = 1
    AND (ID % 10) % 104  = 1
)
SELECT TOP (100) t1.ID, t2.ID, t3.ID
FROM OptimizerUnitsCTE t1
CROSS JOIN OptimizerUnitsCTE t2
CROSS JOIN OptimizerUnitsCTE t3
ORDER BY t1.ID + t2.ID + t3.ID DESC;
Run Code Online (Sandbox Code Playgroud)

我在我的机器上运行了一段时间的查询,估计需要大约 4.5 天才能完成。

总而言之,基数估计不佳使成本为 79590.1 单位的查询花费不到一秒,而成本为 1.45306 单位的查询大约需要 4.5 天。