Sir*_*lot 6 sql-server clustered-index sql-server-2016
我刚刚调试了一个让我完全困惑的问题。
我们的开发数据仓库上的 ETL 转换流程在每天成功运行数月后刚刚失败。使用相同的表架构、索引和数据调用相同存储过程的相同 SSIS 作业在生产中工作正常。
此步骤通常需要不到 2 分钟。今天,在 4 小时后,工作尚未完成,但也没有失败。没有报告的错误。SQL 日志sp_who2中没有任何内容,也没有显示任何阻塞。
该作业会截断临时表,然后插入大约 600,000 行数据。ETL 进程具有对该表的独占访问权。当我检查时,我只能看到等待CXPACKET。
我已将故障追溯到唯一的聚集索引。
该表在标识列上有一个非聚集主键(见下文)
CREATE TABLE [dbo].[Transform_JobCosting_Transaction](
[ETL_TransformKey] [int] IDENTITY(1,1) NOT NULL,
[TransactionId] [varchar](255) NOT NULL,
[KeyType] [varchar](255) NOT NULL,
[FinancialYear] [varchar](255) NOT NULL,
[Job] [varchar](255) NOT NULL,
[Subjob] [varchar](255) NOT NULL,
[AnalysisCode] [varchar](255) NULL,
[etc] [varchar](255) NOT NULL,
[etc] [varchar](255) NOT NULL,
[etc] [varchar](255) NOT NULL
CONSTRAINT [PK_Transform_JobCosting_Transaction] PRIMARY KEY NONCLUSTERED
(
[ETL_TransformKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
问题聚集索引是:
CREATE UNIQUE CLUSTERED INDEX [IDX_Unique] ON [dbo].[Transform_JobCosting_Transaction]
( [FinancialYear] ASC,
[KeyType] ASC,
[TransactionId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Run Code Online (Sandbox Code Playgroud)
有第三个非聚集索引,它根本不影响插入。
我们两个人已经为此工作了 4 个小时。我已经删除并重新添加索引 20-30 次尝试不同组合的选项。
总结:聚集索引块插入。非集群工作正常。
我们已经尝试过:
with tablock提示没有帮助。运行:Microsoft SQL Server 2016 (SP1-CU2) (KB4013106) - Windows Server 2012 R2 Standard 6.3 上的 13.0.4422.0 (X64) Developer Edition(64 位)
任何想法或建议将不胜感激。
让我们退后一步,忘记所有围绕聚集索引的故障排除。您有一个INSERT查询,它过去可以在合理的时间内完成,但现在几小时后就无法完成。为什么该查询现在会很慢?我们来看看预估的计划:
从右往左看,计划是先从 扫描单行Extract_DW_Control_Finance,Extract_JCS_Trans在内侧做一个扫描的循环连接,根据目标表的聚簇键对数据进行排序,再用一个循环连接扫描Extract_GL_Jnl_Trans内侧。第一次加入可能不是问题。该计划实际上不能从并行性中受益,但是对于外部结果集中的一行,扫描Extract_JCS_Trans应该只发生一次。但是,优化器估计该连接中将出现一行。如果该行估计是错误的,那么您最终可能会在Extract_GL_Jnl_Trans.
执行良好的查询的查询计划使用不同的策略。行估计明显不同,它执行散列连接:
我怀疑如果您修复行估计,优化器会为性能不佳的查询选择不同的计划。如果Extract_DW_Control_Finance表总是只有一行,您可以考虑将其移动到局部变量中并可能使用RECOMPILE提示。这可能会导致更好的估计。
至于为什么删除聚集索引会导致问题,我怀疑优化器会在Extract_GL_Jnl_Trans没有聚集索引的情况下进行哈希连接。散列连接不会保留外部输入的顺序,但循环连接会保留顺序。优化器对单行进行排序和执行循环连接的成本可能低于对 356566 行进行哈希连接并稍后执行排序的成本。但是,如果不需要排序,那么进行散列连接的成本可能低于循环连接。这可能都归结为修复您的基数估计。
如果您需要在慢查询运行时进行更多故障排除,并且您使用的是 SQL Server 2016 SP1 ,则可以考虑使用跟踪标志 7412。这应该为您提供有关 SQL Server 在查询计划中“卡住”的位置的线索。如果您能够要求实际计划或直接在 SSMS 中运行查询,您可以使用 sys.dm_exec_query_profiles 或实时查询统计功能。