SQL Server下实现利用SQL Server Agent Job对索引重建实现Balance Load
昨天工作中遇到这样一个场景,有个项目需要把某台服务器下所有的表和索引都启用数据压缩(data_compression=page),已经启用了的表和索引就不需要再压缩一次了。统计一下后发现要运行的REBUILD INDEX代码多达上万条,而整个服务器上的所有需要压缩的数据库对象大小加起来估计接近1TB。这种情况下如果把所有工作都交给一条脚本来完成,估计整个周末都跑不完。那么我们的想法就是用多个SQL Server Agent Job来做完成这个任务,分配单位是表(也就是说把同一张表的所有索引重建任务都分配给Job 1,这样避免出现不同Job间对同时间对同一张表的索引重建导致死锁问题),分配原则是按数据页面总大小依次分配,就像这样:
No Index_Name Pages Assign_To
1 Index1 10000 Job1
1 Index2 9000 Job2
1 Index3 8000 Job3
1 Index4 7000 Job1
.....
下面是实现代码:
/*
this script works to compress pages of tables of all database of the server,
skipping those which were compressed and system databases like master, msdb, tempdb, model
*/ /*first of all, get the datbase list to construct the sql**/ IF object_id('tempdb..#t') IS NOT NULL
BEGIN
DROP TABLE #t
END
GO CREATE TABLE #t(db SYSNAME, object_id INT, index_id INT)
GO IF object_id('tempdb..#t2') IS NOT NULL
BEGIN
DROP TABLE #t2
END
GO CREATE TABLE #t2(ID INT IDENTITY(1,1), db SYSNAME, stm VARCHAR(MAX), dpages INT, object_id INT, index_id INT)
GO DECLARE @db SYSNAME,
@sql VARCHAR(MAX) = '',
@sql2 VARCHAR(MAX) = '' DECLARE cur CURSOR FOR
SELECT name FROM sys.databases WHERE name not in ('master', 'msdb', 'tempdb', 'model') OPEN cur FETCH NEXT FROM cur INTO @db WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = @sql + 'UNION ALL select distinct '''+@db+''' db, object_id, index_id from [' + @db + '].sys.partitions(nolock) where data_compression_desc <> ''PAGE''' + CHAR(13);
SET @sql2 = @sql2 + 'UNION ALL SELECT '''+@db+''' as db, CASE id.type_desc WHEN ''HEAP'' THEN ''ALTER TABLE '+QUOTENAME(@db)+'.'' + QUOTENAME(sch.name) + ''.'' + QUOTENAME(ob.name) + '' REBUILD PARTITION = ALL WITH (DATA_COMPRESSION = PAGE);''
ELSE ''ALTER INDEX '' + QUOTENAME(id.name) + '' ON '+QUOTENAME(@db)+'.'' + QUOTENAME(sch.name) + ''.'' + QUOTENAME(ob.name) + '' REBUILD WITH (DATA_COMPRESSION = PAGE);'' END AS stm, syid.dpages, id.object_id, id.index_id
FROM ['+@db+'].sys.indexes id join
['+@db+'].sys.sysindexes syid(nolock) ON syid.id = id.object_id AND syid.indid = id.index_id join
['+@db+'].sys.objects ob(nolock) ON ob.object_id = id.object_id join
['+@db+'].sys.schemas sch(nolock) ON sch.schema_id = ob.schema_id join
#t non_compr on non_compr.object_id = id.object_id and non_compr.index_id = id.index_id
WHERE ob.type_desc = ''USER_TABLE'' ' + CHAR(13); FETCH NEXT FROM cur INTO @db
END CLOSE cur
DEALLOCATE cur SET @sql = RIGHT(@sql, LEN(@sql)-10) SET @sql2 = RIGHT(@sql2, LEN(@sql2)-10) --INSERT #t EXEC(@sql) /*table #t stores temp data queried from sys.partitions because I found that this DMV runs
slowly when joining other tables in some databases like DW. To avoid it, I store data in a temporary table.**/
INSERT #t EXEC(@sql) /*table #t2 works to output statements to rebuild indexes**/
INSERT #t2(db, stm, dpages, object_id, index_id) EXEC (@sql2) --SELECT * FROM #t2 IF OBJECT_ID('Stage.dbo.table1') IS NOT NULL
DROP TABLE Stage.dbo.table1
GO DECLARE @nbr_of_workers AS SMALLINT
SET @nbr_of_workers = 6; --actually @nbr_of_workers should be the number plus 1 ;WITH bal_load AS (
SELECT db, object_id, dpages as obj_dpages, ROW_NUMBER() OVER (PARTITION BY groupfactor ORDER BY dpages DESC) AS group_nbr FROM (
SELECT db, object_id, dpages, NTILE((SELECT COUNT(DISTINCT db+CAST(object_id AS VARCHAR)) FROM #t2)/@nbr_of_workers) OVER (ORDER BY dpages DESC) AS groupfactor FROM (
SELECT db, object_id, SUM(dpages) dpages FROM #t2 GROUP BY db, object_id) T) T) SELECT t.id, t.db, t.stm, t.dpages, t.object_id, t.index_id , bal_load.obj_dpages, bal_load.group_nbr, 0 AS compressed
INTO Stage.dbo.table1
FROM #t2 t JOIN bal_load ON bal_load.db = t.db AND bal_load.object_id = t.object_id
ORDER BY bal_load.group_nbr, bal_load.db, bal_load.obj_dpages DESC, bal_load.object_id CREATE UNIQUE CLUSTERED INDEX CLST_IX_table1 ON Stage.dbo.table1(ID);
GO
Stage.dbo.table1这张表存储了所有要run的命令,然后group_nbr这个栏位表明哪些命令属哪个job
然后在各个job的T-SQL代码里面就这样写:
IF EXISTS(SELECT * FROM Stage.dbo.table1(NOLOCK) WHERE compressed = 0 AND group_nbr=1)
BEGIN
IF OBJECT_ID('tempdb..#t') IS NOT NULL DROP TABLE #t
CREATE TABLE #t(row_nbr INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, ID INT, stm VARCHAR(MAX)) DECLARE @cmd VARCHAR(MAX), @ID INT, @stm VARCHAR(MAX), @curr_row_nbr INT = 1, @max_row_nbr INT INSERT #t(ID, stm)
SELECT ID, stm
FROM Stage.dbo.table1(NOLOCK)
WHERE compressed = 0 AND group_nbr=1; SET @max_row_nbr = SCOPE_IDENTITY(); WHILE @curr_row_nbr <= @max_row_nbr
BEGIN
BEGIN TRY
SELECT @ID = ID, @stm = stm FROM #t WHERE row_nbr = @curr_row_nbr;
EXEC(@stm);
UPDATE Stage.dbo.table1 SET compressed = 1 WHERE ID = @ID;
SET @curr_row_nbr = @curr_row_nbr + 1;
END TRY
BEGIN CATCH
--SELECT ERROR_MESSAGE()
SET @curr_row_nbr = @curr_row_nbr + 1;
CONTINUE
END CATCH
END
END
搞定
SQL Server下实现利用SQL Server Agent Job对索引重建实现Balance Load的更多相关文章
- SQL Server中是否可以准确获取最后一次索引重建的时间?
在SQL Server中,我们能否找到索引的创建时间?最后一次索引重建(Index Rebuild)的时间? 最后一次索引重组(INDEX REORGANIZE)的时间呢? 答案是我们无法准确的找到 ...
- ORACLE11g下如何利用SQL DEVELOPER连接上数据库
最近在学习数据库的相关内容,在sqlplus敲了几天命令行窗口后,想尝试一下用sql developer 连接上数据库但一直没有实现.在网上查询了相关资料后现在终于弄好了,就来写下此篇博文与大家分享! ...
- PL/SQL Developer下设置“长SQL自己主动换行”
***********************************************声明*************************************************** ...
- mybatis的sql中使用$会出现sql注入示例
mybatis的sql中使用$会出现sql注入示例: 模拟简单登录场景: 页面代码: function login(){ //sql注入 var user = { username : "' ...
- SQL Server 执行计划利用统计信息对数据行的预估原理以及SQL Server 2014中预估策略的改变
前提 本文仅讨论SQL Server查询时, 对于非复合统计信息,也即每个字段的统计信息只包含当前列的数据分布的情况下, 在用多个字段进行组合查询的时候,如何根据统计信息去预估行数的. 利用不同字段 ...
- 利用sql server直接创建日历
看到网上有高手直接用sql查询创建日历,也想自己动手实践一遍.笔者这里的实现和网上的都没有什么区别,思路也没有什么新意.觉得好玩,就把它记下来吧. 一.准备知识1.sql的with关键字关于with和 ...
- 利用本地SQL Server维护计划来维护SQL Database
On-Premise的SQL Server提供了维护计划来定期.定时的维护SQL Server.一般的做法是:定义SQL Server Agent Jobs,而后维护计划帮助我们定期.定时执行SQL ...
- 利用SQL Server 2008 R2创建自动备份计划
本文主要利用SQL Server 2008 R2自带的"维护计划"创建一个自动备份数据的任务. 首先,启动 Sql Management studio,确保"SQL Se ...
- Windows Server 2003 Sp2 下无法安装SQL Server 2008 Management Studio Express问题
Windows Server 2003 Sp2 下无法安装SQL Server 2008 Management Studio Express问题钉子 发表于 2010-5-22 1:42:51问题描述 ...
随机推荐
- 【桌面程序搞界面再也不怕了】:迅雷BOLT入门(一)开篇 附程序和源码
本来想多蛤一下前因后果,突然意兴阑珊不想多说啦,直接帖效果吧. 这个是用迅雷BOLT把原来写的一个IE拦截器的界面重写了一下.界面效果是直接从单位的大屏系统改过来的,其中文本框部分,还请设计大屏的小姑 ...
- php 设计API之优化 记
服务器端 可以考虑使用rest实现,清晰url:put http://aa.com/news 客户端 curl实现muliti机制,实现多线程并发,节省多接口调用的时间 curl实现keepalive ...
- hdu 1028 Ignatius and the Princess III
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1028 题目大意:3=1+1+1=1+2=3 :4=4=1+1+1+1=1+2+1=1+3:所以3有3种 ...
- Python大数据依赖包安装
一.安装 先安装python2.7.6,win下的numpy这些包需要直接匹配版本,然后安装“numpy-1.8.1-win32-superpack-python2.7”和“scipy-0.16.0- ...
- C#异常处理策略
1.如果某些异常,本组件无法处理,不要捕获,但要声明有这个异常.例如SecurityException. 2.如果某些异常,本组件可以处理,捕获并处理它,不再声明此异常.例如DirectoryNotF ...
- RabbitMQ 3.6 安装
1. 首先安装这个 http://www.erlang.org/downloads 2. 再安装这个 http://www.rabbitmq.com/install-windows.html 3. 添 ...
- [百度空间] [原]DLL导出实例化的模板类
因为模板是在编译的时候根据模板参数实例化的,实例化之后就像一个普通的类(函数),这样才有对应的二进制代码;否则,没有模板参数,那么编译器就不知道怎么生成代码,所以生成的DLL就没有办法导出模板了.但是 ...
- javascript禁止复制网页内容,兼容三大浏览器
javascript禁止复制网页内容可以通过以下方式实现:禁止鼠标右键+禁止选中文本. 代码很简单,只需要在head标签的javascript内加入以下两行代码即可. document.onconte ...
- URAL题解—不断跟新中
1014:简单题,忘了0的情况可以是10,== 1219:找呀找规律,满足N*(N-1)/2+1=X;就是1 的情况了
- Chapter 4
1.Python中有四种函数:全局函数,局部函数,lambda函数,方法.其中全局函数与局部函数对比理解,局部函数就是定义在某函数之内的函数,否则就是全局函数,lambda函数就是表达式,方法就跟对象 ...