SQL Server中用户定义的表类型的性能

KMB*_*KMB 13 t-sql sql-server user-defined-types table-valued-parameters sql-server-2008-r2

我们一直在使用用户定义的表类型将整数列表传递给我们的存储过程.

然后我们使用它们连接到存储过程查询中的其他表.

例如:

CREATE PROCEDURE [dbo].[sp_Name]
(
    @Ids [dbo].[OurTableType] READONLY  
)
AS
    SET Nocount ON

    SELECT
        *
    FROM
        SOMETABLE
        INNER JOIN @Ids [OurTableType] ON [OurTableType].Id = SOMETABLE.Id
Run Code Online (Sandbox Code Playgroud)

在使用更大的数据集时,我们发现这方面的表现很差.

我们用来加快速度的一种方法是将内容转储到临时表中,然后将其加入.

例如:

CREATE PROCEDURE [dbo].[sp_Name]
(
    @Ids [dbo].[OurTableType] READONLY  
)
AS
    SET Nocount ON
    CREATE TABLE #TempTable(Id INT)
    INSERT INTO #TempTable
    SELECT Id from @Ids

    SELECT
        *
    FROM
        SOMETABLE
        INNER JOIN #TempTable ON #TempTable.Id = SOMETABLE.Id

    DROP TABLE #TempTable
Run Code Online (Sandbox Code Playgroud)

这确实显着提高了性能,但我希望对这种方法以及我们未考虑的任何其他后果有所了解.关于为什么这改善性能的解释也可能是有用的.

NB有时我们可能需要传递的不仅仅是一个整数,因此我们不使用逗号分隔列表或类似的东西.

Sol*_*zky 17

之前已经讨论过这个话题.JOIN性能不佳的主要原因是表值参数(TVP)是表变量.表变量不保留统计信息,并且查询优化器看起来只有1行.因此他们可以做一些事情INSERT INTO Table (column_list) SELECT column_list FROM @TVP;但不是JOIN.

有几件事要试图解决这个问题:

  1. 将所有内容转储到本地临时表(您已经在执行此操作).这里的技术缺点是你正在复制传入TVP的数据tempdb(TVP和临时表都存储他们的数据).

  2. 也许尝试将用户定义的表类型定义为具有群集主键.您可以在该[Id]字段内联执行此操作:

    [ID] INT NOT NULL PRIMARY KEY
    
    Run Code Online (Sandbox Code Playgroud)

    不确定这对性能有多大帮助,但值得一试.

  3. 您可以尝试添加OPTION (RECOMPILE)到查询中.这是一种让查询优化器查看表变量中有多少行的方法,以便它可以有适当的估计值.

    SELECT column_list
    FROM   SOMETABLE
    INNER JOIN @Ids [OurTableType]
            ON [OurTableType].Id = SOMETABLE.Id
    OPTION (RECOMPILE);
    
    Run Code Online (Sandbox Code Playgroud)

    这里的缺点是你有一个RECOMPILE,每次调用这个proc时需要额外的时间.但这可能是整体净收益.

PS.不要这样做RECOMPILE.始终指定列列表.除非做类似的事情WITH (MEMORY_OPTIMIZED = ON).

  • 感谢您的建议,我们对2和3进行了改进。但是在这种情况下,选项1仍然是最快的。我了解复制数据的开销。 (2认同)
  • @KMB仅供参考,如果您仍然感兴趣,我还添加了2个选项。SQL Server 2008 R2中没有一个可用,但是已经3年了,所以也许您已经升级,或者将来会...即使没有,也可能会帮助其他人。 (2认同)