表值参数连接性能

问题描述

我想将名称列表传递给存储过程,然后执行左联接。我已经将名称列表作为表值参数传递了。

CREATE PROCEDURE [DBO].[INSERTANDGETLATESTNAMES]
    (@list [dbo].[NamesCollection] READONLY)
AS
BEGIN
    INSERT INTO [dbo].[Employee](NAME)
    OUTPUT INSERTED.NAME
        SELECT NamesCollection.Name 
        FROM @list AS NamesCollection
        LEFT JOIN [dbo].[Employee] AS emp ON NamesCollection.Name = emp.Name 
        WHERE emp.Name IS NULL
END

用户定义的表格类型:

CREATE TYPE [dbo].[NamesCollection] AS TABLE
                                       (
                                            [NAME] [varchar](50) NULL
                                       )
GO

在上述情况下,sql Server不会维护有关表值参数的统计信息,这将影响连接性能。如果性能较慢,那么我可以通过逗号分隔的字符串传递名称列表并编写一个函数来拆分表并将表返回到存储过程吗?

CREATE FUNCTION split_string_XML
    (@in_string VARCHAR(MAX),@delimiter VARCHAR(1))
RETURNS @list TABLE(NAMES VARCHAR(50))
AS
BEGIN
    DECLARE @sql_xml XML = Cast('<root><U>'+ Replace(@in_string,@delimiter,'</U><U>')+ '</U></root>' AS XML)
    
    INSERT INTO @list(NAMES)
        SELECT f.x.value('.','VARCHAR(50)') AS NAMES
        FROM @sql_xml.nodes('/root/U') f(x)
        WHERE f.x.value('.','VARCHAR(50)') <> ''

    RETURN
END
GO

CREATE FUNCTION split_string_delimiter
    (@in_string VARCHAR(MAX),@delimiter VARCHAR(1))
RETURNS @list TABLE(NAME VARCHAR(50))
AS
BEGIN
    INSERT INTO @list(NAME)
        SELECT value AS NAMES
        FROM STRING_SPLIT(@in_string,@delimiter);

    RETURN
END
GO

解决方法

使用STRING_SPLIT优于使用XML PATH进行拆分。如果可以使用STRING_SPLIT,则可以使用JSON PATH

使用JSON PATH,将JSON variable转换为行集,然后将其插入#temporary table,而不是@table variable,这取决于您的SQL Server版本,#temporary tables的表现更好处理大量数据时。

此外,如果您想向JSON variable添加新字段,则无需编辑table type。由于引用,在编辑table type时很困难。

,

使用表值参数的SELECT非常简单。 这只是一个联接,假设表变量的基数计算为一个,并假设dbo.Employee.Name已建立索引并且列类型匹配,则该联接将使用循环联接来实现,而循环联接是最快的选择情况。

只需确保正确索引了dbo.Employee.Name。