重组聚集索引时从二级读取数据的问题

Yar*_*lav 7 sql-server availability-groups sql-server-2014 index-maintenance

我们在 SQL Server 2014 SP2 CU5(3 个节点)中有一个 AOAG。有一个读取提交的快照隔离级别为ON的数据库。我们有一个压缩的大表。我们在这个表上的一些更大的查询是在辅助中执行的。

然后在主节点上有一个夜间作业来重新组织几个表上的索引。当它遇到上述表的聚集索引时,我们会收到以下错误:

访问数据库 'yyyy' 中的表 'xxxx' 中的版本化行时事务中止。未找到请求的版本化行,因为尝试创建版本的操作不允许可读的辅助访问。

在某些时候,大查询正在执行带有提示的读取READUNCOMMITTED。我认为这是这个错误的原因,所以我删除了它们。但是错误仍然存​​在。

有任何想法吗?

当前设置:

  • 02 次要处于同步模式
  • 03 次要异步模式

AOAG 电流设置

表详细信息

  • 行数:122.567.668
  • 总空间MB:18.460
  • 已用空间MB:18.238

定义:

CREATE TABLE [dbo].[big_table](
[ID] [int] NOT NULL IDENTITY(1, 1),
1 [int] NULL,
2 [datetime] NULL,
3 [int] NULL,
4 [int] NULL CONSTRAINT [DF_ccc_bUnits] DEFAULT ((0)),
5 [money] NULL,
6 [money] NULL,
7 [int] NULL,
8 [int] NULL CONSTRAINT [DF_ccc_MinDays] DEFAULT ((0)),
9 [int] NULL,
10 [int] NULL,
11 [float] NULL,
12 [money] NULL,
13 [int] NULL,
14 [int] NULL,
15 [nvarchar] (200) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
16 [money] NULL,
17 [money] NULL,
18 [int] NULL,
19 [int] NULL,
20 [money] NULL,
21 [money] NULL,
22 [money] NULL,
23 [money] NULL,
24 [money] NULL,
25 [datetime] NOT NULL CONSTRAINT [DFcccadded] DEFAULT (getdate()),
26 [nvarchar] (50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
27 [money] NOT NULL CONSTRAINT [DFcccBrf] DEFAULT ((0)),
29 [money] NOT NULL CONSTRAINT [DFcccHB] DEFAULT ((0)),
30 [money] NOT NULL CONSTRAINT [DFcccFB] DEFAULT ((0)),
31 [money] NOT NULL CONSTRAINT [DFcccAllBoards] DEFAULT ((0)),
32 [money] NOT NULL CONSTRAINT [DFcccChildBrf] DEFAULT ((0)),
33 [money] NOT NULL CONSTRAINT [DFcccChildHB] DEFAULT ((0)),
34 [money] NOT NULL CONSTRAINT [DFcccChildFB] DEFAULT ((0)),
35 [money] NOT NULL CONSTRAINT [DFcccChildAllBoards] DEFAULT ((0)),
36 [int] NULL CONSTRAINT [DFcccShow_1] DEFAULT ((0)),
37 [timestamp] NOT NULL,
38 [money] NULL,
39 [money] NULL,
40 [money] NULL,
41 [money] NULL,
42 [money] NULL,
43 [money] NULL,
44 [money] NULL,
45 [money] NULL,
46 [int] NOT NULL CONSTRAINT [DFcccReleaseHour] DEFAULT ((0)),
47 [int] NULL,
48 [int] NULL,
49 [money] NULL,
50 [money] NULL,
51 [float] NULL
) ON [PRIMARY]
WITH (DATA_COMPRESSION = PAGE)
GO
CREATE UNIQUE CLUSTERED INDEX [IXccc] ON [dbo].[big_table] (1, 2) WITH (FILLFACTOR=90, DATA_COMPRESSION = PAGE) ON [PRIMARY]
GO
ALTER TABLE [dbo].[big_table] ADD CONSTRAINT [PKccc] PRIMARY KEY NONCLUSTERED ([ID]) WITH (DATA_COMPRESSION = PAGE) ON [secondary]
GO
CREATE UNIQUE NONCLUSTERED INDEX [IXcccstamp] ON [dbo].[big_table] (36) INCLUDE (1, 2) WITH (FILLFACTOR=100) ON [PRIMARY]
GO
Run Code Online (Sandbox Code Playgroud)

Yar*_*lav 2

因此,在用尽所有可能的解决方案后,我们向 Microsoft 提出了支持案例。他们要求运行一个工具来在流程运行时收集一些信息,然后进行分析。这是他们的答案:

  • 如果命令在启动重组索引作业之前启动,则您选择命令运行良好
  • 如果选择命令在重新组织作业启动后启动,则该命令将失败。
  • 发现上述行为是AG中的预期行为。
    • 尽管由于行版本控制,读取操作不采用共享锁,但这些操作仍采用架构稳定性 (Sch-S) 锁,这可能会阻止应用 DDL 更改的重做操作。DDL 操作包括 ALTER/DROP 表和视图,但不包括存储过程的 DROP 或 ALTER。
    • 在我们的例子中,当重新组织索引在主重做操作上运行时,在辅助副本上执行相同的重做操作并获取 Sch-M(架构修改锁),当 select 命令尝试访问相同的副本时,它无法获取 Sch-S(架构稳定性)锁,因为它已被具有 Sch-M 锁的重做线程占用。
    • 在这种情况下,您的应用程序会生成错误,包括超时错误。
  • 为了避免这种情况,建议将重新组织索引任务安排在非工作时间

我们没有“非营业时间”,我们 24/7/365 运行。不是一个明确的答案,但至少我们知道这个问题的根本原因。因此,方法是临时更改连接字符串,以便失败的任务将从主 AG 节点读取,而不是在重新索引运行当天从辅助 AG 节点读取。