我有一种情况,我必须决定是接收 XML 作为存储过程的输入参数,还是接收逗号分隔值列表,并使用多表值函数解析它们。
从逻辑上讲,我更喜欢 XML 而不是 udfs,因为 udfs 会导致很多性能问题。但我看到后端的 XML 也使用表值函数来解析 xml。我想知道 XML 是否真的比多表 UDF 好,如果是,是什么让它更好?
CREATE FUNCTION [dbo].[tmp_array_commaValues] ( @string varchar(4000))
RETURNS @final TABLE(Value varchar(100))
AS
begin
WITH tmp_cte(start, stop) AS
(
SELECT 1, CHARINDEX(',' , @string )
UNION ALL
SELECT stop + 1, CHARINDEX(',' ,@string , stop + 1)
FROM tmp_cte
WHERE stop > 0
)
insert into @final
SELECT SUBSTRING(@string , start, CASE WHEN stop > 0 THEN stop-start ELSE 4000 END) AS stringValue
FROM tmp_cte
return
end
/* query */
Select value
From [dbo].[tmp_array_commaValues]('TAG,ABC,ZYX,BAG,TRY,LAG,LEAD,NETHERLANDS,TAG1,ABC1,ZYX1,BAG1,TRY1,SUN12,NANGE1')
/********** XML *********/
Declare @xml XML = '<root><id>Tag</id><id>Lag</id>
<id>Tag1</id><id>Lag1</id>
<id>Tag2</id><id>Lag2</id>
<id>Tag3</id><id>Lag3</id>
<id>Tag4</id><id>Lag4</id>
<id>Tag5</id><id>Lag5</id>
<id>Tag6</id><id>Lag6</id>
<id>Tag7</id><id>Lag7</id>
</root>'
select t.c.value('.','varchar(100)') as string
From @xml.nodes('root/id/text()') As t(c)
UDF 的执行计划: https ://www.brentozar.com/pastetheplan/?id=SJpX2DMwi
XML 的执行计划: https ://www.brentozar.com/pastetheplan/?id=ByQv2PMvo
这不一定是真的。糟糕的代码无论放在哪里都会导致性能问题。但是某些类型的 UDF 有一些缺点:
最好的做法是通常不使用标量函数,因为它们有很多缺点,而单语句表值函数就很好。多语句表值函数问题较少,因为它们仅在查询计划中引用它们的地方被序列化,但整个查询计划仍然可以有其他并行化区域。
如需进一步阅读有关 SQL Server 中并行性抑制的内容,请参阅 Paul White 的文章Forcing a Parallel Query Execution Plan 。
与大多数性能问题一样,我想说这完全取决于您使用 XML 与多语句表值函数进行的操作。使用您提供的执行计划,快速浏览一下,似乎 MSTVF 的性能可能更好(因为它处理的数据更少,并且通常只是一个更简单的执行计划,步骤更少)。但我不能下定论。
您可以将事件探查器或扩展事件与 SQL:BatchCompleted 事件一起使用,或者运行
SET IO, TIME STATISTICS ON
并查看Messages
SSMS 中的窗口以查看CPU Time
、Elapsed Time
和其他TIME STATISTICS
,并IO STATISTICS
帮助衡量哪个执行效率更高。具有 lessCPU Time
、 lowerElapsed Time
和/或 lessLogical Reads
的是您可以用来确定哪个性能更高的一般因素。此外,Erik Darkling 建议在过程中使用表值参数通常是一个很好的做法。这将是我的 3 个选择中的首选。
是的,数据已经以表格格式呈现,不需要(在 SQL Server 上)处理就可以到达那里。使用它们唯一明显的缺点是它们作为一个表变量出现,SQL Server 不对其维护统计信息。我通常的解决方法是立即
SELECT
将表变量放入临时表,然后在整个过程中使用该临时表。我强烈建议尽快升级,因为它落后于最新的四个主要版本,并且也不再受 Microsoft 支持。延长支持日期于去年 7 月(2022 年)结束。