使用隐式类型转换插入会导致基数估计警告

Dan*_*lam 8 sql-server t-sql execution-plan cardinality-estimates

我最近在做一些性能测试时注意到了这一点。当我将一个值插入到需要隐式转换(例如bigintinto nvarchar)的列中时,我收到一条警告:

表达式中的类型转换(CONVERT_IMPLICIT(nvarchar(50),[tempdb].[dbo].[#MyFunIntTable].[EvenCoolerColumn],0))可能会影响查询计划选择中的“基数估计”。

作为一个关心的公民,我检查了所有明显的嫌疑人,并最终深入研究了 XML 以确认它实际上是关于插入表的警告。问题是,我无法弄清楚为什么这会影响基数估计。如果我在连接中或在具有更多逻辑的地方执行此操作,那将是有道理的,但是实际插入操作不应该存在基数估计不匹配,对吗?

我注意到当它不仅仅是一个简单的查询时会发生这种情况 - 只要插入了多个值,或者我们从表中提取一个值,我们就会点击这个。

这个问题吸引了一些潜在的重复,包括:

我认为它与这些问题不同,因为我实际上没有对这个专栏做任何事情。我没有在过滤器、排序、分组、连接或函数中使用它 - 这些东西中的任何一个都会使场景变得更加复杂。我所做的只是将 a 插入bigint到 a 中nvarchar,这永远不会影响我能想到的有意义的基数估计。

我特别想从答案中寻找的是:

  1. 解释为什么我在没有任何兴趣的情况下收到此警告 - 是否只是 SQL Server 会保守并报告,即使它不会影响计划选择?
  2. 什么基数估计在这里实际上存在风险,基于该基数估计的不准确性,哪些操作会发生变化?
  3. 是否存在这会影响计划选择的情况?显然,如果我开始加入或过滤转换后的列,它可以,但按原样?
  4. 除了更改数据类型(假设这是数据模型交互方式的要求)之外,还有什么可以防止它发出警告的吗?

我用下面的简单例子重新创建了它(粘贴计划

DROP TABLE IF EXISTS #MyFunStringTable;
DROP TABLE IF EXISTS #MyFunIntTable;

CREATE TABLE #MyFunStringTable
(
  SuperCoolColumn nvarchar(50) COLLATE DATABASE_DEFAULT NULL
);

CREATE TABLE #MyFunIntTable
(
  EvenCoolerColumn bigint NULL
);

INSERT INTO #MyFunIntTable
( EvenCoolerColumn )
VALUES
( 1 ),
( 2 ),
( 3 ),
( 4 ),
( 5 );

INSERT INTO #MyFunStringTable
( SuperCoolColumn )
  SELECT EvenCoolerColumn
    FROM #MyFunIntTable;

INSERT INTO #MyFunStringTable
( SuperCoolColumn )
VALUES
( 1 );

INSERT INTO #MyFunStringTable
( SuperCoolColumn )
VALUES
( 1 ),
( 2 );

INSERT INTO #MyFunStringTable
( SuperCoolColumn )
  SELECT 1;

INSERT INTO #MyFunStringTable
( SuperCoolColumn )
SELECT 1
UNION ALL
SELECT 2;

INSERT INTO #MyFunStringTable
( SuperCoolColumn )
  SELECT 1
    FROM #MyFunIntTable;
Run Code Online (Sandbox Code Playgroud)

Pau*_*ite 10

与其他执行计划警告一样,这个警告是信息性的。如果您的查询执行缓慢,或者您注意到基数估计不正确,警告将提供有关在哪里寻找可能原因的信息。

作为一个纯粹的实际问题,这几乎是它的结束。触发此优化器警告的确切条件没有记录。

也就是说,我将详细介绍一下,以满足您的一点好奇心。

1. 解释为什么我在没有任何兴趣的情况下收到此警告 - 是否只是 SQL Server 会保守并报告,即使它不会影响计划选择?

查询优化器的基数估计组件有一些有趣的事情。该组件跟踪查询树中每个逻辑运算符的各种属性和其他信息。这包括直方图(来自磁盘,或完全在内存中派生)、域信息、函数依赖等。

在您的具体示例中,当已知转换的输入是单调的但输出不是时,将触发警告。从integer文字到bigint保留此属性的转换。从bigintnvarchar(50)没有转换。

当存在单个文字整数常量时,解析时常量折叠会nvarchar在优化开始之前将其转换为。这避免了计划中的类型转换以及相关的警告。

原始基数估计器和新基数估计器之间存在详细的内部实现差异,这意味着某些语句将在一个 CE 下生成警告,而不是在另一个 CE 下生成警告。

2. 什么基数估计在这里实际上存在风险,基于该基数估计的不准确,哪些操作会发生变化?

在您的示例语句中,没有。如前所述,转换可能会影响其他内部数据,这可能会影响其他计划运算符或通过优化器采用的代码路径。主要的一点是,要考虑的不仅仅是原始基数估计。内部差异可能会影响索引视图或计算列匹配等内容,以及其他可能性。

3. 是否存在这会影响计划选择的情况?显然,如果我开始加入或过滤转换后的列,它可以,但按原样?

这似乎与上一个问题相同。

4.除了改变数据类型之外,有没有什么办法可以防止它发出警告(假设这是数据模型如何交互的要求)

没有选项可以关闭这些警告。