SQL query with Table variable/Temp Table - 哪个性能好

SQL query with Table variable/Temp Table - which one good in performance

SQL 问题: 这个插入查询性能好吗?


UserIds 列表是可变的,其长度为 10、20 ... 直到 500。

WITH Users
  AS (SELECT [Id] from [electro].[User] Where [Id] IN (4438,15473,22497,22494,4425,4426,22496))
  INSERT INTO [electro].[ElectronicCorrespondenceInbox] ([UserId], [ElectronicCorrespondenceId], [CreatedAt])
  SELECT [User].[Id], [Corrs].[Id], GETDATE()
FROM [electro].[ElectronicCorrespondence] AS [Corrs], [Users] AS [User]
WHERE [Corrs].[Published] = 0;


创建包含用户 ID 的临时变量是个好主意吗?

带有 Table 变量的选项 2#:

DECLARE @USERS TABLE
([UserId] INT NOT NULL);

INSERT INTO @USERS
VALUES (2350), (4438), (15473), (22497), (22494), (4425), (4426), (22496);

INSERT INTO [electro].[ElectronicCorrespondenceInbox] ([UserId], [ElectronicCorrespondenceId], [CreatedAt])
SELECT [User].[UserId], [Corrs].[Id], GETDATE()
FROM [electro].[ElectronicCorrespondence] AS [Corrs], @USERS AS [User]
WHERE [Corrs].[Published] = 0;

首先,stop 使用旧式连接语法 - 它不精确且容易出错;使用现代显式 join 语法,参见 Bad join habbits.

在这种情况下使用 temp table 是不必要的,并且在大多数情况下不可取,因为行数可能未知。 SQL 2019 有一个叫做 deferred table 变量编译 的东西,它可以提高 table-变量的临时查询性能,但对于缓存仍然有问题执行计划。

这是因为当您使用 table 变量时,尤其是在 SQL2019 之前,SQL 服务器在任何意义上都将其视为变量,因为变量可以存储一个 单个 值,并且 SQL 服务器假设只有 1 行,无论它实际上包含 1 行还是 100 万行。

这可能会导致在连接到 table 变量时执行计划不佳,导致 unsuitable 连接操作、table 扫描操作和低估的内存授予导致 tempdb 使用,因为它总是被假定为轻量级操作。

您的查询最好按如下方式编写,因为您要在结果中引入笛卡尔积,所以最好始终使用正确的连接语法进行明确说明。这还假定您 需要 将 ID 值列表与 Users table 中实际存在的 ID 值列表相关联,正如您的第一个查询所暗示的那样

insert into electro.ElectronicCorrespondenceInbox (UserId, ElectronicCorrespondenceId, CreatedAt)
select u.Id, ec.Id, GetDate()
from electro.ElectronicCorrespondence ec
cross join electro.Users u 
where ec.Published = 0
and u.id in (4438,15473,22497,22494,4425,4426,22496)

如果您实际上不需要这个,正如您的第二个查询所暗示的那样,那么您可以直接在您的 CTE 中包含 values 的列表,而无需触及您的 User table

 with users as (
    select id from (values(4438),(15473),(22497),(22494),(4425),(4426),(22496))v(Id)
)

最后,如果这打算成为您向其传递可变数量的 ID 值的过程的一部分,例如使用 table-type 参数,您可能会发现将传入的 table 类型参数的值插入适当的 #temporary table 并在查询中使用它会产生最佳性能。