当存储过程同时运行多次时,临时表过滤索引创建被阻止

Bry*_*bok 4 sql-server filtered-index sql-server-2014 temporary-tables

SQL Server 2014 中是否存在任何已知的阻塞问题,这些问题特定于在初始表创建后在临时表上创建一个或多个筛选索引?(即不是内联索引创建)

我不允许发布实际代码;因此,我更改了表/列名称以保护无辜者。下面具有代表性但非常粗略的逻辑包含在存储过程的开头。

我相信,当存储过程同时运行多次时会发生阻塞。根据我的 DMV 查询,存储过程在第一个非聚集索引创建语句中被阻塞。

CREATE TABLE #temp_table_name_goes_here (
    [the_first_col] BIGINT NULL
    ,[the_second_col] INT NULL
    ,[another_col] VARCHAR(20) NULL
    );

CREATE INDEX tmp_indx_temp_table_name_goes_here_1 ON #temp_table_name_goes_here (the_first_col)
WHERE the_first_col IS NOT NULL;

CREATE INDEX tmp_indx_temp_table_name_goes_here_2 ON #temp_table_name_goes_here (the_second_col)
WHERE the_second_col IS NOT NULL; 
Run Code Online (Sandbox Code Playgroud)

Eri*_*ing 5

再现!

我能够使用SQL Query Stress重现您的问题,使用您的示例,并更改内容以创建内联索引,正如 Paul 建议的那样:

CREATE TABLE #temp_table_name_goes_here
     (
         the_first_col BIGINT NULL,
         the_second_col INT NULL,
         another_col VARCHAR(20) NULL,
         INDEX tmp_indx_temp_table_name_goes_here ( the_first_col ) 
               WHERE the_first_col IS NOT NULL,
         INDEX tmp_indx_outstanding_inventory ( the_second_col ) 
               WHERE the_second_col IS NOT NULL
     );
Run Code Online (Sandbox Code Playgroud)

坚果

当然,SQS 运行了 200 个并发会话进行了 20 次迭代,因此需要一些工作才能实现。

我使用的是 SQL Server 2017,因此启用Trace Flag 3427并没有改变这种情况。

如果 tempdb 未在您的系统上进行最佳配置,我将从那里开始:

  • 每个内核一个数据文件,最多 8 个内核
  • 启用跟踪标志 1117 和 1118

如果您仍有问题,我会向 Microsoft 开立支持案例。像这样的可扩展性问题应该是重中之重。

跟进

在绊倒这个问题之后,我决定使用表变量重新尝试测试。在与上述相同的情况下,观察到相同的争用。

DECLARE @temp_table_name_goes_here TABLE
     (
         the_first_col BIGINT NULL,
         the_second_col INT NULL,
         another_col VARCHAR(20) NULL,
         INDEX tmp_indx_temp_table_name_goes_here ( the_first_col ) 
               WHERE the_first_col IS NOT NULL,
         INDEX tmp_indx_outstanding_inventory ( the_second_col ) 
               WHERE the_second_col IS NOT NULL
     );
Run Code Online (Sandbox Code Playgroud)

根据Jonathan Fite 的评论,我还在开始时使用显式 DROP IF EXISTS(或旧式检查 NOT NULL object_id)重新运行临时表测试:

我以前遇到过这个错误。我的解决方案是在创建它之前添加显式删除索引和临时表(DROP IF EXISTS)。只有在同一个会话多次运行存储过程时才会发生这种情况。

确实有帮助。争用要么不存在,要么最小化。

在最后添加显式 DROP TABLE 或 DROP IF EXISTS 会产生奇怪的效果:奇怪的是,争用转为删除临时表:

坚果