玩转SQL Server复制回路の变更数据类型、未分区表转为分区表

玩转SQL Server复制回路の变更数据类型、未分区表转为分区表

复制的应用:

初级应用:读写分离、数据库备份

高级应用:搬迁大型数据库(跨机房)、变更数据类型、未分区表转为分区表

京东的复制专家 菠萝 曾经写过文章、在数据库大会上也做过演讲,但是我相信真正按照菠萝兄的文章自己去做一次实验的人应该不多

京东的复制专家 菠萝 的文章地址:Replication的犄角旮旯(一)--变更订阅端表名的应用场景

为什麽要玩转复制,大家想象一下:变更数据类型、未分区表转为分区表 这些业务场景经常都会发生,特别在数据量特别大的公司

变更数据类型:没有其他特别好的办法,数据量大,锁表时间会比较长

未分区表转为分区表:有时候一张表的数据量已经很多了,比如体积已经达到100G,那么这时候需要做表分区,方法是重建聚集索引或者导数据

上面的方法不多不少都有一些缺陷,对于数据量特别大的情况下,如果超出业务的预期停机时间……菊花残,满地伤

常见场景:

1、变更其中的自增列主键,int-》bigint ,将表改为表分区

2、100G+的大表

3、单次最长停机时间:为1小时

复制回路,一次搞定

下面介绍一下,如何在一个实例下,通过三个数据库,建立一个复制回路,完成上面的需求

实验环境:一台电脑,一个SQL Server实例,SQL Server2012, Windows7

复制类型为事务复制

结构图

从上图可以看出,由于都是在同一个实例,同一台机器下,所以机器磁盘需要有足够的磁盘空间!!

因为[testloopbackA]库有一个[testAltertype]表100G,复制到[testloopbackB]库[testAltertype]表100G

复制到[testloopbackC]库[testAltertype]表100G,最后复制回去[testloopbackA]库[testAltertype]表100G

加上生成的快照文件,当然快照文件可能会压缩,但是一定要保证有足够的磁盘空间

下面是具体演示

1、建库脚本

USE [master]
GO

/****** Object:  Database [testloopbackA]    Script Date: 2015/6/3 8:21:01 ******/
CREATE DATABASE [testloopbackA]
 CONTAINMENT = NONE
 ON  PRIMARY
( NAME = N‘testloopbackA‘, FILENAME = N‘D:\DataBase\testloopbackA.mdf‘ , SIZE = 30720KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
 FILEGROUP [FG_testChangepartition_Id_01]
( NAME = N‘FG_testChangepartition_Id_01_data‘, FILENAME = N‘D:\DataBase\testloopbackA\FG_testChangepartition_Id_01_data.ndf‘ , SIZE = 24576KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1048576KB ),
 FILEGROUP [FG_testChangepartition_Id_02]
( NAME = N‘FG_testChangepartition_Id_02_data‘, FILENAME = N‘D:\DataBase\testloopbackA\FG_testChangepartition_Id_02_data.ndf‘ , SIZE = 24576KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1048576KB )
 LOG ON
( NAME = N‘testloopbackA_log‘, FILENAME = N‘D:\DataBase\testloopbackA_log.ldf‘ , SIZE = 2432KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO

USE [master]
GO

/****** Object:  Database [testloopbackB]    Script Date: 2015/6/3 8:22:11 ******/
CREATE DATABASE [testloopbackB]
 CONTAINMENT = NONE
 ON  PRIMARY
( NAME = N‘testloopbackB‘, FILENAME = N‘D:\DataBase\testloopbackB.mdf‘ , SIZE = 30720KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
 FILEGROUP [FG_testChangepartition_Id_01]
( NAME = N‘FG_testChangepartition_Id_01_data‘, FILENAME = N‘D:\DataBase\testloopbackB\FG_testChangepartition_Id_01_data.ndf‘ , SIZE = 24576KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1048576KB ),
 FILEGROUP [FG_testChangepartition_Id_02]
( NAME = N‘FG_testChangepartition_Id_02_data‘, FILENAME = N‘D:\DataBase\testloopbackB\FG_testChangepartition_Id_02_data.ndf‘ , SIZE = 24576KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1048576KB )
 LOG ON
( NAME = N‘testloopbackB_log‘, FILENAME = N‘D:\DataBase\testloopbackB_log.ldf‘ , SIZE = 2432KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO

USE [master]
GO

/****** Object:  Database [testloopbackC]    Script Date: 2015/6/3 8:22:14 ******/
CREATE DATABASE [testloopbackC]
 CONTAINMENT = NONE
 ON  PRIMARY
( NAME = N‘testloopbackC‘, FILENAME = N‘D:\DataBase\testloopbackC.mdf‘ , SIZE = 30720KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
 FILEGROUP [FG_testChangepartition_Id_01]
( NAME = N‘FG_testChangepartition_Id_01_data‘, FILENAME = N‘D:\DataBase\testloopbackC\FG_testChangepartition_Id_01_data.ndf‘ , SIZE = 24576KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1048576KB ),
 FILEGROUP [FG_testChangepartition_Id_02]
( NAME = N‘FG_testChangepartition_Id_02_data‘, FILENAME = N‘D:\DataBase\testloopbackC\FG_testChangepartition_Id_02_data.ndf‘ , SIZE = 24576KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1048576KB )
 LOG ON
( NAME = N‘testloopbackC_log‘, FILENAME = N‘D:\DataBase\testloopbackC_log.ldf‘ , SIZE = 2432KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
GO

下面分区方案和分区函数都在三个库上执行

--1.创建分区函数
CREATE PARTITION FUNCTION
Fun_testChangepartition_Id(INT) AS
RANGE LEFT
FOR VALUES(2)

--2.创建分区方案
CREATE PARTITION SCHEME
[Sch_testChangepartition_Id] AS
PARTITION [Fun_testChangepartition_Id]
TO([FG_testChangepartition_Id_01],[FG_testChangepartition_Id_02])

建表脚本

USE [testloopbackA]
GO

--更改数据类型
CREATE TABLE [testAltertype](id INT IDENTITY(1,1) PRIMARY KEY,name NVARCHAR(100))
GO
--变分区表
CREATE TABLE [testChangepartition](id INT IDENTITY(1,1) PRIMARY KEY,name NVARCHAR(100))
GO

--插入测试数据
INSERT INTO [dbo].[testAltertype]
        ( [name] )
VALUES  ( N‘nihao‘  -- name - nvarchar(100)
          )

INSERT INTO [dbo].[testChangepartition]
        ( [name] )
VALUES  ( N‘nihao‘  -- name - nvarchar(100)
          )

SELECT * FROM [testAltertype]
SELECT * FROM [testChangepartition]

2、在[testloopbackB]库先建好2个表

USE [testloopbackB]
GO

--更改数据类型
CREATE TABLE testAltertype_new(id BIGINT IDENTITY(1,1) PRIMARY KEY,name NVARCHAR(100))
GO
--变分区表
CREATE TABLE testChangepartition_new(id INT IDENTITY(1,1) PRIMARY KEY,name NVARCHAR(100)) ON [Sch_testChangepartition_Id](id)
GO

3、创建[testloopbackA]库到[testloopbackB]库的发布,这一步很关键,因为在发布的时候需要修改项目属性,在发布属性里,还需要选择快照为字符类型

testChangepartition_new表

testAltertype_new表

[testloopbackA]库到[testloopbackB]库的复制

4、建立[pub_testloopbackAtotestloopbackB]发布的订阅

5、在[testloopbackB]库里, 将[testAltertype_new]表和[testChangepartition_new]表里的id列里的不用于复制设置为"是"

[testAltertype_new]表

[testChangepartition_new]表

6、测试

在[testloopbackA]库的[testAltertype]表和[testChangepartition]表各插入一些记录

USE [testloopbackA]
GO

--插入测试数据
INSERT INTO [dbo].[testAltertype]
        ( [name] )
VALUES  ( N‘nihao2‘  -- name - nvarchar(100)
          )

INSERT INTO [dbo].[testChangepartition]
        ( [name] )
VALUES  ( N‘nihao2‘  -- name - nvarchar(100)
          )

SELECT * FROM [testAltertype]
SELECT * FROM [testChangepartition]

在[testloopbackB]库就能看到新插入的记录

USE [testloopbackB]
GO

SELECT * FROM [dbo].[testAltertype_new]
SELECT * FROM [dbo].[testChangepartition_new]

在[testloopbackB]库里执行

USE [testloopbackB]
GO
--查看分区架构文件组分布
SELECT  CONVERT(VARCHAR(MAX), ps.name) AS partition_scheme ,
        p.partition_number ,
        CONVERT(VARCHAR(MAX), ds2.name) AS filegroup ,
        CONVERT(VARCHAR(MAX), ISNULL(v.value, ‘‘), 120) AS range_boundary ,
        STR(p.rows, 9) AS rows
FROM    sys.indexes i
        JOIN sys.partition_schemes ps ON i.data_space_id = ps.data_space_id
        JOIN sys.destination_data_spaces dds ON ps.data_space_id = dds.partition_scheme_id
        JOIN sys.data_spaces ds2 ON dds.data_space_id = ds2.data_space_id
        JOIN sys.partitions p ON dds.destination_id = p.partition_number
                                 AND p.object_id = i.object_id
                                 AND p.index_id = i.index_id
        JOIN sys.partition_functions pf ON ps.function_id = pf.function_id
        LEFT JOIN sys.Partition_Range_values v ON pf.function_id = v.function_id
                                                  AND v.boundary_id = p.partition_number
                                                  - pf.boundary_value_on_right
WHERE   i.object_id = OBJECT_ID(‘testChangepartition_new‘)
        AND i.index_id IN ( 0, 1 )
ORDER BY p.partition_number

数据已经入到相应分区

7、继续将[testloopbackB]库的[testAltertype_new]表和[testChangepartition_new]表复制到[testloopbackC]

这一步需要注意:[testAltertype_new]表不需要再跟[testloopbackA]库到[testloopbackB]库的复制那样设置项目属性->XX_new,只需要保持默认就行了

[testChangepartition_new]表跟刚才一样,需要设置项目属性->XX_new

先在[testloopbackC]库建好 [testChangepartition_new]表,[testAltertype_new]表不需要预先建立

USE [testloopbackC]
GO
--变分区表
CREATE TABLE testChangepartition_new(id INT IDENTITY(1,1) PRIMARY KEY,name NVARCHAR(100)) ON [Sch_testChangepartition_Id](id)
GO

8、建[testloopbackB]库到[testloopbackC]库的发布

8、建立订阅[testloopbackC]库

启动快照初始化

然后需要对[testChangepartition_new]表设置不用于复制 为“是”

[testAltertype_new]表不需要设置

9、测试

[testloopbackA]库插入的记录,[testloopbackC]库马上能看到

USE [testloopbackC]
go

--查看分区架构文件组分布
SELECT  CONVERT(VARCHAR(MAX), ps.name) AS partition_scheme ,
        p.partition_number ,
        CONVERT(VARCHAR(MAX), ds2.name) AS filegroup ,
        CONVERT(VARCHAR(MAX), ISNULL(v.value, ‘‘), 120) AS range_boundary ,
        STR(p.rows, 9) AS rows
FROM    sys.indexes i
        JOIN sys.partition_schemes ps ON i.data_space_id = ps.data_space_id
        JOIN sys.destination_data_spaces dds ON ps.data_space_id = dds.partition_scheme_id
        JOIN sys.data_spaces ds2 ON dds.data_space_id = ds2.data_space_id
        JOIN sys.partitions p ON dds.destination_id = p.partition_number
                                 AND p.object_id = i.object_id
                                 AND p.index_id = i.index_id
        JOIN sys.partition_functions pf ON ps.function_id = pf.function_id
        LEFT JOIN sys.Partition_Range_values v ON pf.function_id = v.function_id
                                                  AND v.boundary_id = p.partition_number
                                                  - pf.boundary_value_on_right
WHERE   i.object_id = OBJECT_ID(‘testChangepartition_new‘)
        AND i.index_id IN ( 0, 1 )
ORDER BY p.partition_number

--分区区间
--SELECT  *  FROM    sys.partition_range_values

数据入到相应分区

10、跟第7步一样,但是这一次是[testloopbackC]库到[testloopbackA]库

先在[testloopbackA]库建好 [testChangepartition_new]表,[testAltertype_new]表不需要预先建立

USE [testloopbackA]
GO
--变分区表
CREATE TABLE testChangepartition_new(id INT IDENTITY(1,1) PRIMARY KEY,name NVARCHAR(100)) ON [Sch_testChangepartition_Id](id)
GO

11、建[testloopbackC]库到[testloopbackA]库的发布

12、建立订阅[testloopbackA]库

启动快照初始化

然后需要对[testChangepartition_new]表设置不用于复制 为“是”

[testAltertype_new]表不需要设置

13、测试

[testloopbackA]库插入的记录,[testloopbackA]库马上能看到

USE [testloopbackA]
GO
SELECT * FROM [dbo].[testAltertype_new]
SELECT * FROM [dbo].[testChangepartition_new]

USE [testloopbackA]
go

--查看分区架构文件组分布
SELECT  CONVERT(VARCHAR(MAX), ps.name) AS partition_scheme ,
        p.partition_number ,
        CONVERT(VARCHAR(MAX), ds2.name) AS filegroup ,
        CONVERT(VARCHAR(MAX), ISNULL(v.value, ‘‘), 120) AS range_boundary ,
        STR(p.rows, 9) AS rows
FROM    sys.indexes i
        JOIN sys.partition_schemes ps ON i.data_space_id = ps.data_space_id
        JOIN sys.destination_data_spaces dds ON ps.data_space_id = dds.partition_scheme_id
        JOIN sys.data_spaces ds2 ON dds.data_space_id = ds2.data_space_id
        JOIN sys.partitions p ON dds.destination_id = p.partition_number
                                 AND p.object_id = i.object_id
                                 AND p.index_id = i.index_id
        JOIN sys.partition_functions pf ON ps.function_id = pf.function_id
        LEFT JOIN sys.Partition_Range_values v ON pf.function_id = v.function_id
                                                  AND v.boundary_id = p.partition_number
                                                  - pf.boundary_value_on_right
WHERE   i.object_id = OBJECT_ID(‘testChangepartition_new‘)
        AND i.index_id IN ( 0, 1 )
ORDER BY p.partition_number

--分区区间
--SELECT  *  FROM    sys.partition_range_values

数据进入到相应分区

接下来就是找个适当的时间,比如凌晨, 停写, 拆复制, 改表名    打完 收工!!



总结

在搭建复制回路的过程当中,本人发现加字段是不行的,比如testloopbackA库testAddcolumn_new表有四个字段

然后预先在testloopbackB库建立testAddcolumn_new表,并增加一个字段,在快照初始化的时候报错

错误消息:
进程无法向表“"dbo"."testAddcolumn_new"”进行大容量复制。 (源: MSSQL_REPL,错误号: MSSQL_REPL20037)
获取帮助: http://help/MSSQL_REPL20037
已达到文件末尾,缺少结束符或字段数据不完整
若要获取详细说明初始化订阅表时所遇到的错误的错误文件,请执行在下面显示的 bcp 命令。有关该 bcp 实用工具及其支持的选项的详细信息,请参阅 BOL。 (源: MSSQLServer,错误号: 20253)
获取帮助: http://help/20253
bcp "testloopbackB"."dbo"."testAddcolumn_new" in "E:\DataBase\ReplData\unc\NAME-PC_TESTLOOPBACKA_PUB_TESTLOOPBACKATOTES1cf75016\20150604115556\testAddcolumn_2.bcp" -e "errorfile" -t"\n<x$3>\n" -r"\n<,@g>\n" -m10000 -SNAME-PC -T -w (源: MSSQLServer,错误号: 20253)
获取帮助: http://help/20253

对于大表加字段的情况,可以考虑在停机维护窗口添加或者考虑升级到SQL Server2012 ,SQL Server2012 对加字段已经作了一些修改

对阻塞减少到最低

相关文章:Sql Server 2012新特性 Online添加非空栏位.

如有不对的地方,欢迎大家拍砖o(∩_∩)o 

时间: 2024-10-14 04:40:44

玩转SQL Server复制回路の变更数据类型、未分区表转为分区表的相关文章

SQL Server复制入门(一)----复制简介【转】

SQL Server复制入门(一)----复制简介 简介 SQL Server中的复制(Replication)是SQL Server高可用性的核心功能之一,在我看来,复制指的并不仅仅是一项技术,而是一些列技术的集合,包括从存储转发数据到同步数据到维护数据一致性.使用复制功能不仅仅需要你对业务的熟悉,还需要对复制功能的整体有一个全面的了解,本系列文章旨在对SQL Server中的复制进行一个简单全面的探讨.(PS:在我的上篇文章中我发现某些文章的图片使用mspaint手绘更有感觉,但被很多人吐槽

SQL Server 2005 中的数据类型总结

注:转自土豆网 SQL Server 2005 中的数据类型归纳为下列类别: 精确数字 bigint decimal int numeric smallint money tinyint smallmoney bit 近似数字 float real 日期和时间 datetime smalldatetime 字符串 char text varchar Unicode字符串 nchar ntext nvarchar 二进制字符串 binary image varbinary 其他数据类型 curso

SQL Server复制入门(一)----复制简介

简介 SQL Server中的复制(Replication)是SQL Server高可用性的核心功能之一,在我看来,复制指的并不仅仅是一项技术,而是一些列技术的集合,包括从存储转发数据到同步数据到维护数据一致性.使 用复制功能不仅仅需要你对业务的熟悉,还需要对复制功能的整体有一个全面的了解,本系列文章旨在对SQL Server中的复制进行一个简单全面的探讨.(PS:在我的上篇文章中我发现某些文章的图片使用mspaint手绘更有感觉,但被很多人吐槽,因此在不 考虑个人羞耻感的前提下,本系列文章中的

SQL Server复制出错文章集锦

SQL Server复制出错文章集锦 为了方便大家对数据库复制过程中出错的时候更好地解决问题 本人收集了SQL Server相关复制出错解决的文章   The process could not execute 'sp_repldone/sp_replcounters' on 'ServerName' 潇湘隐者 事物复制遇到的几个错误 万剑齐发 一个事务复制的bug--更新丢失 续 stswordman 复制中发布服务器和订阅服务器内容不一致的解决办法 CareySon 一个事务复制的bug--

sql server 复制表从一个数据库到另一个数据库

sql server 复制表从一个数据库到另一个数据库 /*不同服务器数据库之间的数据操作*/ --创建链接服务器 exec sp_addlinkedserver 'ITSV ', ' ', 'SQLOLEDB ', '远程服务器名或ip地址 ' exec sp_addlinkedsrvlogin 'ITSV ', 'false ',null, '用户名 ', '密码 ' --查询示例 select * from ITSV.数据库名.dbo.表名 --导入示例 select * into 表 f

SQL Server 复制优化

曾搭建了一个复制系统,用于搜索业务,在业务上增加某些特别的功能后,读库压力增加,导致复制延时.通过多种方式进行优化,其中一个是修改复制代理的参数. 写库和分发库之间无复制延时,复制延迟出现在分发库和读库之间. 在SQL Server复制参数方面,主要调整了PacketSize,PacketSize 默认值是4096. ------------------------------------------------------------------------------------------

使用的 SQL Server 版本不支持数据类型“datetime2”解决办法

错误原因,在使用ado.net entity的时候,entity使用的数据库是sqlserver 2008,但后来实际使用中使用的数据库是sqlserver 2005 使用的 SQL Server 版本不支持数据类型“datetime2” The version of SQL Server in use does not support datatype ‘datetime2 解决办法 Open your EDMX in a file editor (or “open with…” in Vis

SQL Server 复制:事务发布(读写分离)

一.背景 在复制的运用场景中,事务发布是使用最为广泛的,我遇到这样一个场景:在YangJiaLeClub数据库中有表.存储过程.视图.用户定义函数,需要提供给其它程序读取放入缓存,程序需要比较及时的获取到这些数据,需要从权限和性能控制的角度出发,我采用了SQL Server的事务复制技术和timestamp,下面只讲述事务复制的搭建过程: 二.实现过程 (一) 环境信息   操作系统 IP 服务器名称 数据库版本 数据库名称 数据库帐号信息 发布服务器 Windows 10 企业版  192.1

使用的 SQL Server 版本不支持数据类型“datetime2”.

错误原因,在使用ado.net entity的时候,entity使用的数据库是sqlserver 2008, 但后来实际使用中使用的数据库是sqlserver 2005, 使用的 SQL Server 版本不支持数据类型“datetime2” The version of SQL Server in use does not support datatype ‘datetime2 解决办法 Open your EDMX in a file editor (or “open with…” in V