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这样的事情。
有几件事要试图解决这个问题:
- 将所有内容转储到本地临时表(您已经在执行此操作)。这里的技术缺点是你在
tempdb
(TVP和临时表存储他们的数据)中复制传入TVP的数据。 - 也许尝试将用户定义的表类型定义为具有群集主键。您可以在
[Id]
字段内联执行此操作:[ID] INT NOT NULL PRIMARY KEY
不确定这对性能有多大帮助,但值得一试。 - 您可以尝试将
OPTION (RECOMPILE)
添加到查询中。这是一种让查询优化器查看表变量中有多少行的方法,以便它可以有适当的估计值。SELECT column_list FROM SOMETABLE INNER JOIN @Ids [OurTableType] ON [OurTableType].Id = SOMETABLE.Id OPTION (RECOMPILE);
这里的缺点是你有一个RECOMPILE
,每次调用此proc时需要额外的时间。但这可能是整体净收益。 - 从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)。 - SQL Server 2019引入了“Table variable deferred compilation”: 使用表变量延迟编译,引用表变量的语句的编译将延迟到语句的第一次实际执行。此延迟编译行为与临时表的行为相同。此更改导致使用实际基数而不是原始的单行猜测。 有关详细信息,请参阅链接的文档。
PS。不要做SELECT *
。始终指定列列表。除非做像IF EXIST(SELECT * FROM)...
这样的事情。
以上是关于SQL Server中用户定义的表类型的性能的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server,如何从用户定义的表类型中删除更新元素?
如何在SQL Server中使用用户定义的表类型插入数据时避免重复记录