我们一直在使用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时需要额外的时间。但这可能是整体净收益。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)。PS。不要做SELECT *
。始终指定列列表。除非做像IF EXIST(SELECT * FROM)...
这样的事情。