Art*_*yan 7 performance sql-server cardinality-estimates query-performance
我有 2 个名称列的表:
CREATE TABLE Test
(
TestID int identity primary key clustered
, Name_Eng nvarchar(50)
, Name_Nat nvarchar(50)
)
Run Code Online (Sandbox Code Playgroud)
现在我需要一个查询来让这个Name列用 分隔,,像这样:
DECLARE @NameColumns NVARCHAR(1024)
SET @NameColumns = STUFF(
(SELECT ',' + 'Test.' + name AS [text()]
FROM ( SELECT c.name
FROM sys.columns c
INNER JOIN sys.tables t ON t.object_id = c.object_id
WHERE t.name = 'Test'
AND c.name LIKE 'Name_%'
) AS D
FOR XML PATH('') ,
TYPE).value('.[1]', 'VARCHAR(MAX)'), 1, 1,
N'')
select @NameColumns
Run Code Online (Sandbox Code Playgroud)
但是这个查询在执行计划中有一个警告:
有什么办法可以消除这个警告吗?
虽然我同意 @Kin 关于数据类型的观点,但我认为这个警告并没有你想象的那么麻烦。您正在执行分组串联,这将比任何转换都要贵几个数量级(正如 Daniel 所说,除非您的目录视图很大 - 如大于物理内存 - 它不太可能影响任何方面估计)。
我会以这种方式编写查询,注意不要使用 varchar 字符串(这也意味着不要N在字符串文字上遗漏前缀),并确保您使用语句终止符:
DECLARE @NameColumns nvarchar(max); -- why 1024 when you use max below?
SET @NameColumns = STUFF(
(SELECT N',Test.' + name AS [text()] FROM
(
SELECT c.name FROM sys.columns AS c
INNER JOIN sys.tables AS t
ON t.object_id = c.object_id
WHERE t.name = N'Test'
AND c.name LIKE N'Name_%'
) AS D FOR XML PATH(N''),
TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'');
SELECT @NameColumns;
Run Code Online (Sandbox Code Playgroud)
即便如此,我仍然不相信有任何方法可以避免隐式转换而不改变输出,就像 Mikael 建议的那样避免TYPE/value()。当您可以实际证明这对查询的性能有一些实质性影响时,我会说担心这一点。在我的测试中,两种不同的形式表现相同(我们每次都在 10 毫秒以下),但是当然,如果我有一个命名的表,Sales & Stuff那么它就Sales & Stuff没有隐式转换。
由于 XML 函数,警告在那里value()。第二个参数 tovalue()是您希望将存储在 XML 中的值转换为什么。您可能会争辩说,这实际上不是隐式转换,而是非常显式的转换,因为您要求它发生。也许是连接项目向微软建议的东西。
重现您所见内容的最简单方法。
declare @X xml;
select @X.value('text()[1]', 'int');
Run Code Online (Sandbox Code Playgroud)
给出这两个警告。
<Warnings>
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[lvalue],0)" />
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[value],0)" />
</Warnings>
Run Code Online (Sandbox Code Playgroud)
如您所见,您也可以使用 int 来获取它,并且每次调用value().
declare @X xml;
select @X.value('text()[1]', 'int'),
@X.value('text()[1]', 'bit');
Run Code Online (Sandbox Code Playgroud)
<Warnings>
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[lvalue],0)" />
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(int,XML Reader with XPath filter.[value],0)" />
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(bit,XML Reader with XPath filter.[lvalue],0)" />
<PlanAffectingConvert ConvertIssue="Cardinality Estimate" Expression="CONVERT_IMPLICIT(bit,XML Reader with XPath filter.[value],0)" />
</Warnings>
Run Code Online (Sandbox Code Playgroud)
转换是在 Stream Aggregate 运算符中完成的,该运算符像这样计算值。
MIN(CASE WHEN [@X] IS NULL
THEN NULL
ELSE
CASE WHEN datalength(XML Reader with XPath filter.[value])>=(128)
THEN CONVERT_IMPLICIT(int,XML Reader with XPath filter.[lvalue],0)
ELSE CONVERT_IMPLICIT(int,XML Reader with XPath filter.[value],0)
END
END)
Run Code Online (Sandbox Code Playgroud)
Table Valued 函数的结果在lvalueorvalue列中返回。该表达式通过使用datalength来确定应该从哪里获取它,然后将其转换为所需的数据类型。
有什么办法可以消除这个警告吗?
就在这里。您TYPE从FOR XML PATH语句中删除指令并删除对value()函数的调用。这样做的一个副作用是,您连接的包含需要在 XML 中编码的字符的值&<>将在您的结果中进行编码。
| 归档时间: |
|
| 查看次数: |
3390 次 |
| 最近记录: |