Rad*_*ača 6 sql-server optimization
我们希望看到 SQL Server 优化器在查询优化期间考虑的查询计划的所有变体。SQL Server 使用querytraceon
选项提供了非常详细的洞察力。例如,QUERYTRACEON 3604, QUERYTRACEON 8615
允许我们打印出 MEMO 结构并QUERYTRACEON 3604, QUERYTRACEON 8619
打印出在优化过程中应用的转换规则列表。这很好,但是,我们在跟踪输出方面有几个问题:
让我用一个更详细的例子来展示它。让我有两个人造表A
和B
:
WITH x AS (
SELECT n FROM
(
VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)
) v(n)
),
t1 AS
(
SELECT ones.n + 10 * tens.n + 100 * hundreds.n + 1000 * thousands.n + 10000 * tenthousands.n + 100000 * hundredthousands.n as id
FROM x ones, x tens, x hundreds, x thousands, x tenthousands, x hundredthousands
)
SELECT
CAST(id AS INT) id,
CAST(id % 9173 AS int) fkb,
CAST(id % 911 AS int) search,
LEFT('Value ' + CAST(id AS VARCHAR) + ' ' + REPLICATE('*', 1000), 1000) AS padding
INTO A
FROM t1;
WITH x AS (
SELECT n FROM
(
VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9)
) v(n)
),
t1 AS
(
SELECT ones.n + 10 * tens.n + 100 * hundreds.n + 1000 * thousands.n AS id
FROM x ones, x tens, x hundreds, x thousands
)
SELECT
CAST(id AS INT) id,
CAST(id % 901 AS INT) search,
LEFT('Value ' + CAST(id AS VARCHAR) + ' ' + REPLICATE('*', 1000), 1000) AS padding
INTO B
FROM t1;
Run Code Online (Sandbox Code Playgroud)
现在,我运行一个简单的查询
SELECT a1.id, a1.fkb, a1.search, a1.padding
FROM A a1 JOIN A a2 ON a1.fkb = a2.id
WHERE a1.search = 497 AND a2.search = 1
OPTION(RECOMPILE,
MAXDOP 1,
QUERYTRACEON 3604,
QUERYTRACEON 8615)
Run Code Online (Sandbox Code Playgroud)
我得到了相当复杂的输出,它描述了具有 15 个组的 MEMO 结构(您可以自己尝试)。这是使用树可视化 MEMO 结构的图片。
从树中可以观察到在优化器找到最终查询计划之前应用了某些规则。例如
join commute
( JoinCommute
)、join to hash join
( JNtoHS
) 或Enforce sort
( EnforceSort
)。如前所述,可以使用QUERYTRACEON 3604, QUERYTRACEON 8619
选项打印出优化器应用的整套重写规则。问题:
JNtoSM
( Join to sort merge
) 重写规则,但是,排序合并运算符不在 MEMO 结构中。我知道排序合并的成本可能更高,但为什么它不在 MEMO 中?LogOp_Get
MEMO 中的运算符是否引用了表 A 或表 B?GetToIdxScan - Get -> IdxScan
在 8619 列表中看到规则,如何将其映射到 MEMO 运算符?关于此的资源数量有限。我已经阅读了许多关于转换规则和 MEMO 的 Paul White 博客文章,但是,上述问题仍未得到解答。谢谢你的帮助。
我将尝试回答您的问题:
1. MEMO 结构似乎只包含查询计划的最终变体或后来重写为最终计划的变体。有没有办法找到“不成功/没有希望”的查询计划?
不,遗憾的是没有办法做到这一点。@Ronaldo 在评论中粘贴了一个很好的链接。我的建议是使用Include Live Query Statistics
并尝试找出是否看到不同的查询计划。使用top 10
、top 1000
、 或*
,您将看到将建议不同的查询计划。您还可以使用query hint
并强制您的查询计划采用不同的模式。基本上“做你自己废弃的查询计划”
2. MEMO 中的运算符不包含对 SQL 部分的引用。例如,LogOp_Get 运算符不包含对特定表的引用。
使用QUERYTRACEON 8605
,我可以看到对该表的引用:
3. 转换规则不包含对 MEMO 算子的精确引用,因此,我们无法确定转换规则转换了哪些算子
GetToIdxScan - Get -> IdxScan
我在您提供的查询中没有看到任何内容。我的建议是使用 UseQUERYTRACEON 8605
或QUERYTRACEON 8606
,那里应该有一个参考。
编辑:
那么“...是否可以在 SQL Server 中查看有关候选计划的更多信息。”
答案是否定的,因为没有其他候选查询计划。事实上,一个常见的误解是 SQL Server 会返回给您最佳的查询计划。SQL Server 根本无法为您计算所有可能的解决方案:这将需要...我不知道...分钟...?小时...?计算每一个解决方案是不可行的。
但是,如果您想调查为什么查询计划选择该模式,您可以使用:
SET SHOWPLAN_ALL ON
: SQL Server 将返回查询计划的每个计算的逻辑树DBCC SHOW_STATISTICS('A', 'PK_A')
:这将显示有关目标表和约束的统计信息。我创建了一个键来向您显示结果,如果您的表被更频繁地查询,您自然会看到更多信息USE HINT('force_legacy_cardinality_estimation')
:将允许您使用以前的基数估计,因此您可以检查使用旧基数估计您的查询计划是否可能更快。 归档时间: |
|
查看次数: |
279 次 |
最近记录: |