在现实场景中,我们经常会遇到修改数据类型的场景,尤其是自增列从INT修改为BIGINT的情况,自增列又通常作为表的主键和聚集索引键,因此修改操作需要按以下步骤来进行

1. 停止对该表的访问(通过禁用权限或停应用的方式实现)

2. 删除非聚集索引

3. 删除主键聚集索引

4. 使用ALTER TABLE ALTER COLUMN来修改

5. 创建主键聚集索引

6. 创建非聚集索引

此方式有以下缺点:

1. 整个ALTER COLUMN操作作为一个事务,需要对将每条数据修改操作记录到日志中,中途撤销修改需要长时间回滚。

2. 根据页面碎片情况,修改类型操作可能造成大量的页拆分,导致日志文件暴增。

3. 影响正常业务的周期较长。

针对大事务和页拆分的问题,可以进行以下改进: 新建表,将现有表中数据导入到新表中,数据导入完成后,修改新表名称为现有表名,当仍无法解决影响周期较长的问题,在导入数据期间,允许程序进行只读访问,降低修改类型操作对业务的影响,但数据长时间不可修改,这对很多重要业务也是不可接受的。

为解决此问题,肖桑提出了复制环路的解决办法,采用多级复制的方式,将旧表数据复制到新表中,然后停止旧表读写,等所有修改同步到新表后,再修改表名,以实现数据类型变更的目的,除前期准备时间外,整个操作对业务影响时间可以控制在几分钟以内。

采用导入新表的方式,为保证新旧两表数据一致,必须限制对旧表的修改操作,如果能保证某一时间点的数据被完整地导入到新表,并且保证在导入过程中所有发生在旧表上的操作被“同步”到新表中,那便可以实现新旧两表在特定时间点数据一致。

实现方式:

1. 使用数据库快照来将旧表中某一点的数据导入到新表

2. 使用更改跟踪来将自快照后所有发生在旧表上的数据变更更新到新表上

测试步骤及测试代码:

1. 对数据库启用更改跟踪

--===================================
--对数据库TesDB2启用CT功能
ALTER DATABASE TesDB2
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)
GO

2. 创建测试表和生成模拟数据

--=====================================
--创建测试表
CREATE TABLE TB001
(
ID INT IDENTITY(1,1) PRIMARY KEY,
C1 NVARCHAR(200)
)
GO
--==================================
--插入数据
INSERT INTO TB001(C1)
SELECT T1.name FROM sys.all_columns T1
GO

3. 对表启用更改跟踪

--===================================
--对表TB001启用CT功能
ALTER TABLE TB001
ENABLE CHANGE_TRACKING
WITH (TRACK_COLUMNS_UPDATED = ON)
GO

4. 创建新表,并将数据导入到新表中

--==================================
--创建测试表
CREATE TABLE TB002
(
ID BIGINT IDENTITY(1,1) PRIMARY KEY,
C1 NVARCHAR(200)
)
GO
--==================================
--将TB001的数据导入到TB002中
--生产环境可以使用快照方式来保证数据一致性
SET IDENTITY_INSERT TB002 ON
INSERT TB002(ID,C1)
SELECT ID,C1 FROM TB001
SET IDENTITY_INSERT TB002 OFF
GO

5. 模拟数据库上变化,然后将禁用账户对表的修改权限

--======================================
--模拟TB001上数据变化
INSERT INTO TB001(C1)
SELECT TOP(100) T1.name
FROM sys.all_columns T1
GO
UPDATE TB001
SET C1='UPDATEDATA'
WHERE ID%10=1
GO
DELETE TB001
WHERE ID%4=1
GO

6. 将在旧表上的删除操作“同步”到新表上

--======================================
--删除TB001中不存在但在TB002中存在的数据
WITH T1 AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY ID
ORDER BY CT.SYS_CHANGE_VERSION DESC) AS RowNum,
*
FROM CHANGETABLE(CHANGES [dbo].[TB001],0) AS CT
),
T2 AS
(
SELECT *
FROM T1
WHERE RowNum = 1
AND SYS_CHANGE_OPERATION = 'D'
)
DELETE FROM [dbo].[TB002]
WHERE ID IN (
SELECT ID FROM T2
)
GO

7. 将在旧表上的删除操作“同步”到新表上

--======================================
--根据TB001中插入和更新的数据来更新TB002
GO
SET IDENTITY_INSERT [dbo].[TB002] ON
;WITH T1 AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY ID
ORDER BY CT.SYS_CHANGE_VERSION DESC) AS RowNum,
*
FROM CHANGETABLE(CHANGES [dbo].[TB001],0) AS CT
),
T2 AS
(
SELECT *
FROM T1
WHERE RowNum = 1
AND (SYS_CHANGE_OPERATION = 'U'
OR SYS_CHANGE_OPERATION = 'I')
),
T3 AS
(
SELECT * FROM [dbo].[TB001]
WHERE ID IN (SELECT ID FROM T2)
),
T4 AS
(
SELECT * FROM [dbo].[TB002]
WHERE ID IN (SELECT ID FROM T2)
)
MERGE T4 AS T
USING T3 AS S
ON T.ID=S.ID
WHEN MATCHED THEN
UPDATE SET T.C1=S.C1
WHEN NOT MATCHED BY TARGET THEN
INSERT(
[ID],
[C1]
)
VALUES
(
[ID],
[C1]
);
SET IDENTITY_INSERT [dbo].[TB002] OFF
GO

8. 检查两表数据是否一致,生产环境中建议使用SP_SPACEUSED来查看表数据

--====================================================
--检查数据是否相同,如果下面查询没有数据,则证明数据一致
SELECT * FROM
(
SELECT * FROM TB001
EXCEPT
SELECT * FROM TB002
) AS T1
UNION
SELECT * FROM
(
SELECT * FROM TB002
EXCEPT
SELECT * FROM TB001
) AS T2
GO

9. 清理测试环境

--==================================
--禁用表级别更改跟踪
ALTER DATABASE [TestDB2]
SET CHANGE_TRACKING = OFF
--==================================
--禁用表级别更改跟踪
ALTER TABLE TB001
DISABLE CHANGE_TRACKING;
--=====================================
--删除测试表
DROP TABLE TB001
DROP TABLE TB002

由于我们追求的是最终数据一致,因此使用ROW_NUMBER() OVER (PARTITION BY ID ORDER BY CT.SYS_CHANGE_VERSION DESC) AS RowNum =1的方式来过滤中间变更,如果使用SYS_CHANGE_COLMNS会“严重”增加代码复杂性,因此采用更新所有字段的暴力方式实现。

如果导入数据的过程持续时间较长,该期间内数据变化较大,可以考虑先实现一次“同步”后,再禁用旧表的访问权限,然后再做一次“同步”操作,以降低最后一次“同步”的运行时间。

--============================================================

好久米写文脏,随便整个妹子镇贴。

使用更改跟踪(ChangeTracking)来实现数据类型变更的更多相关文章

  1. SQL Server 2008中新增的 1.变更数据捕获(CDC) 和 2.更改跟踪

    概述 1.变更数据捕获(CDC)        每一次的数据操作都会记录下来 2.更改跟踪       只会记录最新一条记录   以上两种的区别:         http://blog.csdn.n ...

  2. SQL Server 2008中新增的变更数据捕获(CDC)和更改跟踪

    来源:http://www.cnblogs.com/downmoon/archive/2012/04/10/2439462.html  本文主要介绍SQL Server中记录数据变更的四个方法:触发器 ...

  3. SQL Server 2008新特性——更改跟踪

    在大型的数据库应用中,经常会遇到部分数据的脱机和多个数据库的合并问题.比如现在有一个全省范围使用的应用程序,每个市都部署了单独的相同的应用程序服务器和数据库服务器,每个月需要将全省所有市的数据全部汇总 ...

  4. SQL Server 更改跟踪(Chang Tracking)监控表数据

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 主要区别与对比(Compare) 实现监控表数据步骤(Process) 参考文献(Refere ...

  5. SQL Server审计功能入门:更改跟踪(Change Tracking)

    原文:SQL Server审计功能入门:更改跟踪(Change Tracking) 介绍 更改跟踪是一种轻量型解决方案,它为应用程序提供了一种有效的更改跟踪机制.常规的,自定义变更跟踪和读取跟踪数据, ...

  6. 消息 4900,级别 16,状态 2,第 1 行 对表 'XX.XXX' 执行 ALTER TABLE SWITCH 语句失败。对于已启用更改跟踪的表,不可能切换其分区。请先禁用更改跟踪,再使用 ALTER TABLE SWITCH。

    问题描述: 今天处理切换分区数据的时候出现了这个错误: 消息 4900,级别 16,状态 2,第 1 行 对表 'XX.XXX' 执行 ALTER TABLE SWITCH 语句失败.对于已启用更改跟 ...

  7. Dynamics 365 Customer Enagement中的更改跟踪(change tracking)

    我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...

  8. 如何使用块更改跟踪文件估算RMAN增量备份大小 (Doc ID 1938079.1)

    How to estimate RMAN incremental backup size using block change tracking file (Doc ID 1938079.1) APP ...

  9. 【转载,备忘】SQL Server 更改跟踪(Chang Tracking)监控表数据

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 主要区别与对比(Compare) 实现监控表数据步骤(Process) 参考文献(Refere ...

随机推荐

  1. mysql错误日志

    cat /etc/my.cnf

  2. Eclipse 安装使用 M2Eclipse 插件

    help --> Install New Software --> Add 安装完后需要重启eclipse 通常 Eclipse 会自带 Maven.但可能按自己安装的 Maven 存在版 ...

  3. ApplicationContext(九)初始化非延迟的 bean

    ApplicationContext(九)初始化非延迟的 bean 此至,ApplicationContext 已经完成了全部的准备工作,开始初始化剩余的 bean 了(第 11 步). public ...

  4. PHP TP 生成二维码

    vendor('phpqrcode.phpqrcode'); $value = "http://www.baidu.com";//二维码内容 $errorCorrectionLev ...

  5. 使用flask-alchemy 过程中报错KeyError: 'SQLALCHEMY_TRACK_MODIFICATIONS'

    在网上找了很多, 大多数说是必须要给 SQLALCHEMY_TRACK_MODIFICATIONS 一个默认值,尝试修改alchemy 源码,,但是还是不起作用 最后阅读源码 , self.app = ...

  6. autohotkey快捷键

    ;已经基本修复了输入带shift的时候跟输入法中英文切换之间的冲突 SetStoreCapslockMode, off SetKeyDelay, ^CapsLock:: #UseHook ;用这个和下 ...

  7. No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal

    No goals have been specified for this build. You must specify a valid lifecycle phase or a goal in t ...

  8. php结合layui实现前台加后台操作

    一:前台加载出前端页面: HTML: lay-data="{width:800,height:400, url:'data.php', page:true, id:'test'} js: l ...

  9. SPRING 集成 activemq 的 topic 模式

    概要 activemq 支持两种模式: 1.队列模式 2. 发布订阅者模式,topic有一个主题可以有多个订阅者.这种情况可以将一个消息,分发到多个消费者. 比如我有这样一个案例,用户需要同步,而且需 ...

  10. java的Scanner获取输入内容

    //导入 scanner的包 import java.util.Scanner; Scanner scanner = new Scanner(System.in); System.out.printl ...