sp_ExecuteSQL、性能和表变量

Chr*_*s J 6 sql-server dynamic-sql sql-server-2008-r2

有没有人能够解释我在 SQL Profiler 中看到的一些行为?采取以下两批:

exec sp_executesql N'
    declare @t table (
        x int
    )

    insert into @t (x) select top 10 number from dbo.gennumbers

    select * from @t
    union
    select * from @t
'

exec sp_executesql N'
    select top 10 number from dbo.gennumbers
    union
    select top 10 number from dbo.gennumbers
'
Run Code Online (Sandbox Code Playgroud)

(这是我正在进行的一些重构的简化;实际上,临时表是通过在最终查询中重用的 CTE 填充的,因此通过缓存数据来减轻 SQL Server 需要执行的重复工作量)。

在这个例子中,GenNumbers 只是一个数字表,只有一个列,只包含一个连续运行的数字 - 没什么特别的。

在探查器中,我得到以下结果:

第 1 批,带有临时表:

事件 TextData 读取
SP:StmtCompleted INSERT INTO(...) 27
SP:StmtCompleted SELECT * FROM ... 6
SQL:StmtCompleted exec sp_executesql 170

第 2 批,直接命中:

事件 TextData 读取
SP:StmtCompleted SELECT TOP 10 * ... 6
SQL:StmtCompleted exec sp_executesql 6

我想了解的是SQL:StmtCompleted. 我期望总读取数应等于批次内发生的所有读取数的总和,但是在批次 1 中似乎并非如此 - 事实上,它明显更高。而第 2 批执行单个选择,最终读取 == 实际读取。

执行计划中没有什么明显的东西可以看出这些额外的时间去哪里了,但也许我没有捕捉到正确的事情 - 有没有人对实际发生的事情有任何想法?我想知道我是否需要担心 SQL Server“给”我的额外 100 次读取,因为这个读取计数比实际读取计数高五到六倍。

我假设这与 SQL 需要维护有关临时表的信息有关,但不清楚究竟是什么。任何灯罩都会很有用。

Mar*_*ith 4

当表超出与或语句无关的范围时,CREATE TABLE在开头和结尾有一个隐式。DROP TABLE @TINSERTSELECT

如果替换为表,您应该会看到和语句#temp有一些额外的读取。对我来说,我看到 36 个和 100 个,所以这占了你丢失的 137 个读数中的 136 个。dropcreateCREATEDROP

(带表格的#temp脚本)

EXEC sp_executesql N'
   CREATE TABLE #T 
  ( 
     x INT 
  ) 

INSERT INTO #T 
            (x) 
SELECT TOP 10 number 
FROM   master..spt_values 

SELECT * 
FROM   #T 
UNION 
SELECT * 
FROM   #T 

DROP TABLE #T
'
Run Code Online (Sandbox Code Playgroud)