以下是一个例子:
context.getRemainingTimeInMillis()
运行它并检查等待统计信息:
CREATE TABLE #t
(
id int IDENTITY(1,1) PRIMARY KEY,
ss varchar(50)
)
INSERT INTO #t (ss)
SELECT name FROM master.dbo.spt_values
DELETE FROM #t
SELECT * FROM sys.dm_exec_session_wait_stats WHERE session_id = <spid>
现在在存储过程中放入相同的代码:
session_id wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms
---------- ------------------------------ -------------------- -------------------- -------------------- --------------------
116 SOS_SCHEDULER_YIELD 2 0 0 0
116 MEMORY_ALLOCATION_EXT 125 0 0 0
运行它并再次检查等待统计数据。 我们将看到很多pagelatch_ex等待:
CREATE PROCEDURE dbo.tp_test_temp_latches
AS
BEGIN
CREATE TABLE #t
(
id int IDENTITY(1,1) PRIMARY KEY,
ss varchar(50)
)
INSERT INTO #t (ss)
SELECT name FROM master.dbo.spt_values
DELETE FROM #t
END
我用DBCC TRACEON(8666)检查了执行计划。 第一个示例显示RowSetSharing = 1。 第二个示例显示RowSetSharing = 0。
我有一些大的存储过程,在我当前的项目中使用临时表很多。我想从行集共享中受益,但我不能。我创建了Paul White博客文章,他描述了他如何通过OPTION(QUERYTRACEON 8746)关闭行集共享:changes-to-a-writable-partition-may-fail
是否可以选择打开它?还是其他任何可能性?
更新05/03/2018
我找到了一个解决方法。 为了消除过多的PAGELATCH_EX等待,我们可以使用跟踪标志8692打开“表盘”:
session_id wait_type waiting_tasks_count wait_time_ms max_wait_time_ms signal_wait_time_ms
---------- ----------------------------- -------------------- -------------------- -------------------- --------------------
1043 PAGELATCH_EX 2537 5 0 3
1043 SOS_SCHEDULER_YIELD 2 0 0 0
1043 MEMORY_ALLOCATION_EXT 132 1 0 0
此选项允许读取所有需要的行,而不是更新/删除它们。所以我们将读/写操作分开。这种技术消除了PAGELATCH_EX等待,几乎两次丢弃逻辑读取。这还远不是在存储过程外使用临时表。但它比不使用此选项快两倍。
更新07/03/2018
进一步调查使我再采取一种解决方法(效率更高):
DELETE FROM #t
OPTION (QUERYTRACEON 8692)
排序运算符在内存中工作,而不是像“table spool”那样在tempdb中工作。