GroupData群数据库的还原与优化
一、背景
这个数据库的数据文件mdf大概有83G左右,当还原数据库之后感觉可以做很多性能方面上的调优,合并数据后mdf数据文件大概有59G左右,行压缩后mdf数据文件大概有39G左右,页压缩后mdf数据文件大概有34G左右,这里处于技术研究的目的,讲讲研究的成果分析,不用于商业目的;
二、优化项
我们可以从下面4个不同的方面来优化这两个数据库:
(一)对表进行分区;
(二)创建合适表索引;
(三)使用行压缩,压缩行数据;
(四)重新设计表结构,优化表空间;
三、附加数据库
1.先把11个GroupData(群与成员的关系)数据库附加到数据库,下面的导入SQL语句在原来的基础上做了些修改:统一数据库名,这样做的好处就是后面做处理的时候方便按照顺序执行数据库;
--附加数据库
EXEC sp_attach_db "GroupData01", "D:\DBBackup\QunData\GroupData1_Data.MDF"
EXEC sp_attach_db "GroupData02", "D:\DBBackup\QunData\GroupData2_Data.MDF"
EXEC sp_attach_db "GroupData03", "D:\DBBackup\QunData\GroupData3_Data.MDF"
EXEC sp_attach_db "GroupData04", "D:\DBBackup\QunData\GroupData4_Data.MDF"
EXEC sp_attach_db "GroupData05", "D:\DBBackup\QunData\GroupData5_Data.MDF"
EXEC sp_attach_db "GroupData06", "D:\DBBackup\QunData\GroupData6_Data.MDF"
EXEC sp_attach_db "GroupData07", "D:\DBBackup\QunData\GroupData7_Data.MDF"
EXEC sp_attach_db "GroupData08", "D:\DBBackup\QunData\GroupData8_Data.MDF"
EXEC sp_attach_db "GroupData09", "D:\DBBackup\QunData\GroupData9_Data.MDF"
EXEC sp_attach_db "GroupData10", "D:\DBBackup\QunData\GroupData10_Data.MDF"
EXEC sp_attach_db "GroupData11",
"D:\DBBackup\QunData\GroupData11_Data.MDF"
四、合并数据库
2.修改各个数据库中表的名字:把Group1统一修改为Group01这样格式的,这样做的好处就是在合并数据的时候读取到的数据库的数据是按照顺序插入到表中的,不会造成数据页的拆分;
--格式化表名
USE GroupData01
GO exec sp_rename 'Group1','Group01'
exec sp_rename 'Group2','Group02'
exec sp_rename 'Group3','Group03'
exec sp_rename 'Group4','Group04'
exec sp_rename 'Group5','Group05'
exec sp_rename 'Group6','Group06'
exec sp_rename 'Group7','Group07'
exec sp_rename 'Group8','Group08'
exec sp_rename 'Group9','Group09'
3.创建一个名为GroupData的数据库,设置数据库为简单恢复模式;
4.在GroupData数据库中创建一个临时表:tables,用来保存所有的数据库与表的信息,提供数据库合并用;
--创建临时表
CREATE TABLE [GroupData].[dbo].[tables](
[db_name] [sysname] NULL,
[table_name] [sysname] NULL,
[status] [bit] default 0
) ON [PRIMARY] select db_name,table_name,status from [GroupData].[dbo].[tables] --生成数据库名称与表名称的对应列表
EXEC sp_MSForEachDB 'USE [?];
--插入表信息
INSERT INTO [GroupData].[dbo].[tables]([table_name])
SELECT name from [?].sys.tables where name like ''Group%'' order by name
--更新数据库名称
UPDATE [GroupData].[dbo].[tables] SET [db_name] = ''?'' WHERE [db_name] IS NULL'
五、优化数据库
5.经过评估,11个GroupData数据库的Group表数据的总和大概有15亿,Group表中QunNum(群号)字段的最大值为100219998(可以通过QunInfo11数据库的QunList110表查询到:SELECT MAX(QunNum) FROM [QunInfo11].[dbo].[QunList110]),从业务的角度,可能需要查询某群的信息,所以这里就以QunNum作为分区,每5百万个群作为一个分区,这样计算那就需要21个文件组,假设群成员都比较平均的话,那每个文件组里面就保存了大概7千万左右的群成员关系;
6.下面是一个创建分区脚本的SQL脚本,执行下面的SQL会生成一个新的脚本,执行那个脚本就可以创建21个文件组、分区函数和分区方案;
--生成分区脚本
DECLARE @DataBaseName NVARCHAR(50)--数据库名称
DECLARE @TableName NVARCHAR(50)--表名称
DECLARE @ColumnName NVARCHAR(50)--字段名称
DECLARE @PartNumber INT--分区最大编号
DECLARE @PartNumberBegin INT--分区编号开始值
DECLARE @PartNumberBeginTemp INT--分区编号开始值临时值
DECLARE @PartNumberStr NVARCHAR(50)--分区值字符串
DECLARE @Location NVARCHAR(50)--保存分区文件的路径
DECLARE @Size NVARCHAR(50)--分区初始化大小
DECLARE @FileGrowth NVARCHAR(50)--分区文件增量
DECLARE @FunValue INT--分区分段值增量
DECLARE @FunValueBegin INT--分区分段值开始值
DECLARE @i INT--临时变量
DECLARE @sql NVARCHAR(max) --设置下面变量
SET @DataBaseName = 'GroupData'
SET @TableName = 'Group'
SET @ColumnName = 'QunNum'
SET @PartNumber = 21
SET @PartNumberBegin = 1
SET @Location = 'D:\DBBackup\FG_Group\'
SET @Size = '4096MB'
SET @FileGrowth = '1024MB'
SET @FunValueBegin = 5000000
SET @FunValue = 5000000 SET @sql = 'USE ['+@DataBaseName +']
GO'
PRINT @sql + CHAR(13) --1.创建文件组
SET @i = 1
SET @PartNumberBeginTemp = @PartNumberBegin
PRINT '--1.创建文件组'
WHILE @i <= @PartNumber
BEGIN
SET @PartNumberStr = RIGHT('' + CONVERT(NVARCHAR,@PartNumberBeginTemp),2)
SET @sql = 'ALTER DATABASE ['+@DataBaseName +']
ADD FILEGROUP [FG_'+@TableName+'_'+@ColumnName+'_'+@PartNumberStr+']'
PRINT @sql + CHAR(13)
SET @i=@i+1
SET @PartNumberBeginTemp = @PartNumberBeginTemp+1
END --2.创建文件
SET @i = 1
SET @PartNumberBeginTemp = @PartNumberBegin
PRINT CHAR(13)+'--2.创建文件'
WHILE @i <= @PartNumber
BEGIN
SET @PartNumberStr = RIGHT('' + CONVERT(NVARCHAR,@PartNumberBeginTemp),2)
SET @sql = 'ALTER DATABASE ['+@DataBaseName +']
ADD FILE
(NAME = N''FG_'+@TableName+'_'+@ColumnName+'_'+@PartNumberStr+'_data'',FILENAME = N'''+@Location+'FG_'+@TableName+'_'+@ColumnName+'_'+@PartNumberStr+'_data.ndf'',SIZE = '+@Size+', FILEGROWTH = '+@FileGrowth+' )
TO FILEGROUP [FG_'+@TableName+'_'+@ColumnName+'_'+@PartNumberStr+'];'
PRINT @sql + CHAR(13)
SET @i=@i+1
SET @PartNumberBeginTemp = @PartNumberBeginTemp+1
END --3.创建分区函数
PRINT CHAR(13)+'--3.创建分区函数'
DECLARE @FunValueStr NVARCHAR(MAX)
DECLARE @PNB INT
SET @i = 1
SET @PNB = 1
SET @FunValueStr = convert(NVARCHAR(50),@FunValueBegin) + ','
WHILE @i < @PartNumber-1
BEGIN
SET @FunValueStr = @FunValueStr + convert(NVARCHAR(50),(@FunValueBegin+@PNB*@FunValue)) + ','
SET @i=@i+1
SET @PNB=@PNB+1
END
SET @FunValueStr = substring(@FunValueStr,1,len(@FunValueStr)-1)
SET @sql = 'CREATE PARTITION FUNCTION
[Fun_'+@TableName+'_'+@ColumnName+'](INT) AS
RANGE RIGHT
FOR VALUES('+@FunValueStr+')'
PRINT @sql + CHAR(13) --4.创建分区方案
PRINT CHAR(13)+'--4.创建分区方案'
DECLARE @FileGroupStr NVARCHAR(MAX)
SET @i = 1
SET @PartNumberBeginTemp = @PartNumberBegin
SET @FileGroupStr = ''
WHILE @i <= @PartNumber
BEGIN
SET @PartNumberStr = RIGHT('' + CONVERT(NVARCHAR,@PartNumberBeginTemp),2)
SET @FileGroupStr = @FileGroupStr + '[FG_'+@TableName+'_'+@ColumnName+'_'+@PartNumberStr+'],'
SET @i=@i+1
SET @PartNumberBeginTemp = @PartNumberBeginTemp+1
END
SET @FileGroupStr = substring(@FileGroupStr,1,len(@FileGroupStr)-1)
SET @sql = 'CREATE PARTITION SCHEME
[Sch_'+@TableName+'_'+@ColumnName+'] AS
PARTITION [Fun_'+@TableName+'_'+@ColumnName+']
TO('+@FileGroupStr+')'
PRINT @sql + CHAR(13) --5.分区函数的记录数
PRINT CHAR(13)+'--5.分区函数的记录数'
SET @sql = 'SELECT $PARTITION.[Fun_'+@TableName+'_'+@ColumnName+']('+@ColumnName+') AS Partition_num,
MIN('+@ColumnName+') AS Min_value,MAX('+@ColumnName+') AS Max_value,COUNT(1) AS Record_num
FROM dbo.['+@TableName+']
GROUP BY $PARTITION.[Fun_'+@TableName+'_'+@ColumnName+']('+@ColumnName+')
ORDER BY $PARTITION.[Fun_'+@TableName+'_'+@ColumnName+']('+@ColumnName+');'
PRINT @sql + CHAR(13)
7.下面重新对Group表进行设计,涉及的内容如下:
1) 在GroupData数据库中创建分区表Group,这里已经把原表的ID字段去掉了,这个字段并没有太大的意义;
2) 以[QunNum]和[QQNum]作为聚集索引,而且是唯一的,这个需要开启IGNORE_DUP_KEY = ON选项,这样才可以在批量插入的时候忽略重复值;
3) 对原表[Age]、[Gender]、[Auth]3个字段的数据类型进行了修改,减少占用的空间,
4) 使用刚刚创建好的分区方案,之后创建的索引进行索引对齐;
5) 对表使用行压缩,减少数据库占用空间;
6) 对表进行页压缩会更节省空间?
--创建优化后的Group表
CREATE TABLE [dbo].[Group](
[QunNum] [int] NOT NULL,
[QQNum] [int] NOT NULL,
[Nick] [varchar](20) NULL,
[Age] [tinyint] NULL,
[Gender] [tinyint] NULL,
[Auth] [tinyint] NULL,
CONSTRAINT [PK_Group] PRIMARY KEY CLUSTERED
(
[QunNum] ASC,
[QQNum] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = ON, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION = ROW) ON [Sch_Group_QunNum]([QunNum])
) ON [Sch_Group_QunNum]([QunNum])
GO

(Figure:GroupData原表结构)

(Figure:GroupData新表结构)
8.把11个数据库都合并到新创建的GroupData的Group表中;
--合并数据
DECLARE @tablename sysname
DECLARE @dbname sysname
DECLARE @sql NVARCHAR(max) --游标
DECLARE @itemCur CURSOR
SET @itemCur = CURSOR FOR
SELECT db_name,table_name from [GroupData].[dbo].[tables] OPEN @itemCur
FETCH NEXT FROM @itemCur INTO @dbname,@tablename
WHILE @@FETCH_STATUS=0 BEGIN SET @sql = '
INSERT INTO [GroupData].[dbo].[Group]
([QunNum]
,[QQNum]
,[Nick]
,[Age]
,[Gender]
,[Auth])
SELECT [QunNum]
,[QQNum]
,[Nick]
,[Age]
,[Gender]
,[Auth]
FROM ['+@dbname+'].[dbo].['+@tablename+']' EXEC(@sql) UPDATE [GroupData].[dbo].[tables] SET status = 1 WHERE db_name = @dbname AND table_name = @tablename --返回SQL
PRINT(@sql)PRINT('GO')+CHAR(13) FETCH NEXT FROM @itemCur INTO @dbname,@tablename
END CLOSE @itemCur
DEALLOCATE @itemCur
9.为Group表的QQNum字段创建一个索引,这个索引在进行表联接的时候会用到;
--索引行压缩
CREATE NONCLUSTERED INDEX [IX_Group_QQNum] ON [dbo].[Group]
(
[QQNum] 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, DATA_COMPRESSION = ROW) ON [Sch_Group_QunNum]([QunNum])
GO

(Figure:GroupData表分区记录数)

(Figure:GroupData数据行压缩前)

(Figure:GroupData数据行压缩后)

(Figure:GroupData数据页压缩后)

(Figure:GroupData索引行压缩前)

(Figure:GroupData索引行压缩后)
怎么行压缩后索引的占用空间比压缩前的还要大呢?
--索引页压缩
CREATE NONCLUSTERED INDEX [IX_Group_QQNum] ON [dbo].[Group]
(
[QQNum] 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, DATA_COMPRESSION = PAGE) ON [Sch_Group_QunNum]([QunNum])
GO

(Figure:GroupData索引页压缩后)
怎么页压缩后索引的占用空间比压缩前的还要大呢?
GroupData群数据库的还原与优化的更多相关文章
- QunInfo群数据库的还原与优化
一. 背景 这个数据库的数据文件mdf大概有8.5G左右,当还原数据库之后感觉可以做很多性能方面上的调优,合并数据后mdf数据文件大概有6.2G左右,行压缩后mdf数据文件大概有4.8G左右,页压缩后 ...
- nbu还原集群数据库异常问题
集群数据库软件均已安装完毕,现在想从NBU上还原数据库,但在还原控制文件报错 [oracle@oracle-db1 ~]$ rman target / Recovery Manager: Releas ...
- DB2数据库性能调整和优化(第2版)
<DB2数据库性能调整和优化(第2版)> 基本信息 作者: 牛新庄 出版社:清华大学出版社 ISBN:9787302325260 上架时间:2013-7-3 出版日期:2013 年7月 开 ...
- 近千节点的Redis Cluster高可用集群案例:优酷蓝鲸优化实战(摘自高可用架构)
(原创)2016-07-26 吴建超 高可用架构导读:Redis Cluster 作者建议的最大集群规模 1,000 节点,目前优酷在蓝鲸项目中管理了超过 700 台节点,积累了 Redis Clus ...
- Thinkphp3.2 备份数据库和还原数据的方法
其实Thinkphp框架并没有自带备份数据库的功能,但是细心的朋友可能会发现Thinkphp的一套内容管理系统oneThink是有备份数据库和还原数据的功能的. 所以今天我就来聊一聊,oneThink ...
- DM8数据库备份还原的原理及应用
(本文部分内容摘自DM产品技术支持培训文档,如需要更详细的文档,请查询官方操作手册,谢谢) 一.原理 1.DM8备份还原简介 1.1.基本概念 (1)表空间与数据文件 ▷ DM8表空间类型: ▷ SY ...
- SQL Server 数据库备份还原和数据恢复
认识数据库备份和事务日志备份 数据库备份与日志备份是数据库维护的日常工作,备份的目的是在于当数据库出现故障或者遭到破坏时可以根据备份的数据库及事务日志文件还原到最近的时间点将损失降到最低点. 数据 ...
- 如何用Dummy实例执行数据库的还原和恢复
今天实验了一下,如何在所有文件,包括数据文件,在线日志文件,控制文件都丢失的情况下,利用RMAN备份恢复和还原数据库.该实验的重点是用到了Dummy实例. 具体步骤如下: 备份数据库 [oracle@ ...
- 《SQL Server企业级平台管理实践》读书笔记——关于SQL Server数据库的还原方式
本篇是继上篇的备份方式,本篇介绍的是还原方案,在SQL Server在2005以上现有的还原方案一般分为以下4个级别的数据还原: 1.数据库完整还原级别: 还原和恢复整个数据库.数据库在还原和恢复操作 ...
随机推荐
- 故障重现(内存篇2),JAVA内存不足导致频繁回收和swap引起的性能问题
背景起因: 记起以前的另一次也是关于内存的调优分享下 有个系统平时运行非常稳定运行(没经历过大并发考验),然而在一次活动后,人数并发一上来后,系统开始卡. 我按经验开始调优,在每个关键步骤的加入如 ...
- SQL Server表分区
什么是表分区 一般情况下,我们建立数据库表时,表数据都存放在一个文件里. 但是如果是分区表的话,表数据就会按照你指定的规则分放到不同的文件里,把一个大的数据文件拆分为多个小文件,还可以把这些小文件放在 ...
- c#与java的区别
经常有人问这种问题,用了些时间java之后,发现这俩玩意除了一小部分壳子长的还有能稍微凑合上,基本上没什么相似之处,可以说也就是马甲层面上的相似吧,还是比较短的马甲... 一般C#多用于业务系统的开发 ...
- Android raw to bmp
Android raw 格式转 bmp 图像 raw 保存的为裸数据,转换时都需要把它转成RGBA 的方式来显示.其中: 8位RAW: 四位RGBA 来表示一位灰度; 24位RAW: 三位RGB相同, ...
- Node.js:理解stream
Stream在node.js中是一个抽象的接口,基于EventEmitter,也是一种Buffer的高级封装,用来处理流数据.流模块便是提供各种API让我们可以很简单的使用Stream. 流分为四种类 ...
- [C#] 简单的 Helper 封装 -- RegularExpressionHelper
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- ASP.NET MVC开发:Web项目开发必备知识点
最近加班加点完成一个Web项目,使用Asp.net MVC开发.很久以前接触的Asp.net开发还是Aspx形式,什么Razor引擎,什么MVC还是这次开发才明白,可以算是新手. 对新手而言,那进行A ...
- UWP开发之Mvvmlight实践七:如何查找设备(Mobile模拟器、实体手机、PC)中应用的Log等文件
在开发中或者后期测试乃至最后交付使用的时候,如果应用出问题了我们一般的做法就是查看Log文件.上章也提到了查看Log文件,这章重点讲解下如何查看Log文件?如何找到我们需要的Packages安装包目录 ...
- 【走过巨坑】android studio对于jni调用及运行闪退无法加载库的问题解决方案
相信很多小伙伴都在android开发中遇到调用jni的各种巨坑,因为我们不得不在很多地方用到第三方库so文件,然而第三方官方通常都只会给出ADT环境下的集成方式,而谷歌亲儿子android studi ...
- ASP.NET MVC5----常见的数据注解和验证
只要一直走,慢点又何妨. 在使用MVC模式进行开发时,数据注解是经常使用的(模型之上操作),下面是我看书整理的一些常见的用法. 什么是验证,数据注解 验证 从全局来看,发现逻辑仅是整个验证的很小的一部 ...