gbe*_*ven 6 sql-server sql-server-2016 cardinality-estimates
使用 SQL Server 2016 我试图理解为什么我在运行这个 T-SQL 语句时收到这个警告(我选择了表变量以便于测试。这发生在具有int类型列的数据库表中):
declare @test as table(
col1 int
)
insert into @test (col1)
values(30500600)
select LEFT(test.col1, 2)
from @test as test
Run Code Online (Sandbox Code Playgroud)
30按预期返回,但在检查执行计划时,我看到以下SELECT语句的警告:
表达式中的类型转换 (CONVERT_IMPLICIT(varchar(12),[test].[col1],0)) 可能会影响查询计划选择中的“CardinalityEstimate”
如果我在不从表中拉出的情况下运行相同的:
select LEFT(30500600, 2)
Run Code Online (Sandbox Code Playgroud)
30 按预期返回,执行计划中没有警告。
两个语句都应该LEFT()在int类型上执行,所以我不明白为什么一个返回警告而另一个不返回。这里发生了什么?
编辑:
我已经尝试将col1数据类型声明更改为varchar并清除了错误。但这仍然没有向我解释为什么select LEFT(30500600, 2)如果我int直接将 an传递给LEFT()函数,它本身不会引起警告。
我试着cast给varchar原查询:LEFT(cast(test.col1 as varchar(12)), 2)返回相同的警告。
可能重复
链接重复指出计算列是该用户的问题。我的示例中没有计算列,所以这不是问题。这使我进入了关于使用CONCAT函数隐式转换为字符串类型的答案的第二部分,该函数也相同LEFT。在我上面编辑的第二段中,我曾经CAST明确地转换为,varchar所以我认为不会发生转换?我显然在这里遗漏了一些东西。
此查询中没有“类型转换/基数估计”警告的原因:
SELECT LEFT(30500600, 2);
Run Code Online (Sandbox Code Playgroud)
...是因为没有基数估计。 这是一个传递给确定性函数的常量表达式 - 保证只返回一个“行”。我认为解释就这么简单,因为警告更多是关于潜在的基数问题(而不仅仅是类型转换的简单存在)。
如果我得到该语句的估计执行计划,它只是一个“无查询选择”元素:
<?xml version="1.0" encoding="utf-16"?>
<ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.518" Build="13.0.5081.1" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
<BatchSequence>
<Batch>
<Statements>
<StmtSimple StatementCompId="1" StatementId="1" StatementText="select LEFT(30500600, 2)" StatementType="SELECT WITHOUT QUERY" RetrievedFromCache="false" />
</Statements>
</Batch>
</BatchSequence>
</ShowPlanXML>
Run Code Online (Sandbox Code Playgroud)
就其价值而言,即使是表变量版本也不会在 SQL Server 2017 中显示警告(因为当转换不可能影响基数估计时,这确实是一个毫无意义的警告 - 如您的示例所示)。
需要明确的是,该警告并非总是毫无意义。拿这个例子:
SELECT message_id
INTO #SomeNumbers
from sys.messages;
SELECT *
FROM #SomeNumbers
WHERE LEFT(message_id, 2) = '50';
Run Code Online (Sandbox Code Playgroud)
这将 280,192 行放入临时表中。SELECT 查询有此警告,并且警告是合法的。SQL Server 估计有 28,019.2 个匹配行(表的 10%),而实际上只有 2,156 个匹配行(<表的 1%)。
关于您将此输入转换为LEFT函数的示例,请注意警告已从 略微更改CONVERT_IMPLICIT为仅CONVERT:
表达式中的类型转换 (CONVERT(varchar(12),[test].[col1],0)) 可能会影响查询计划选择中的“CardinalityEstimate”
因此,您只是将隐式转换替换为显式转换,这仍然需要警告。