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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL Server中用户定义的表类型的性能相关的知识,希望对你有一定的参考价值。

我们一直在使用User-Defined Table Types将整数列表传递给我们的存储过程。

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

例如:

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

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

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

例如:

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

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

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

答案

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

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

  1. 将所有内容转储到本地临时表(您已经在执行此操作)。这里的技术缺点是你在tempdb(TVP和临时表存储他们的数据)中复制传入TVP的数据。
  2. 也许尝试将用户定义的表类型定义为具有群集主键。您可以在[Id]字段内联执行此操作: [ID] INT NOT NULL PRIMARY KEY 不确定这对性能有多大帮助,但值得一试。
  3. 您可以尝试将OPTION (RECOMPILE)添加到查询中。这是一种让查询优化器查看表变量中有多少行的方法,以便它可以有适当的估计值。 SELECT column_list FROM SOMETABLE INNER JOIN @Ids [OurTableType] ON [OurTableType].Id = SOMETABLE.Id OPTION (RECOMPILE); 这里的缺点是你有一个RECOMPILE,每次调用此proc时需要额外的时间。但这可能是整体净收益。
  4. 从SQL Server 2014开始,您可以利用内存中OLTP并为用户定义的表类型指定WITH (MEMORY_OPTIMIZED = ON)。有关详细信息,请参阅Scenario: Table variable can be MEMORY_OPTIMIZED=ON。我听说这绝对有帮助。遗憾的是,在SQL Server 2014和SQL Server 2016 RTM中,此功能仅适用于64位企业版。但是,从SQL Server 2016 SP1开始,此功能可供所有版本使用(可能的例外是SQL Server Express LocalDB)。
  5. SQL Server 2019引入了“Table variable deferred compilation”: 使用表变量延迟编译,引用表变量的语句的编译将延迟到语句的第一次实际执行。此延迟编译行为与临时表的行为相同。此更改导致使用实际基数而不是原始的单行猜测。 有关详细信息,请参阅链接的文档。

PS。不要做SELECT *。始终指定列列表。除非做像IF EXIST(SELECT * FROM)...这样的事情。

以上是关于SQL Server中用户定义的表类型的性能的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server,如何从用户定义的表类型中删除更新元素?

SQL Server:关于用户定义的表类型的 ltrim

在 SQL Server 数据库之间传递用户定义的表类型

如何在SQL Server中使用用户定义的表类型插入数据时避免重复记录

在 SQL Server Management Studio 中使用执行过程 - 如何格式化用户定义的表类型的值?

使用 JDBC 将用户定义的表类型传递给 SQL Server 存储过程