昨天工作中遇到这样一个场景,有个项目需要把某台服务器下所有的表和索引都启用数据压缩(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的更多相关文章

  1. SQL Server中是否可以准确获取最后一次索引重建的时间?

    在SQL Server中,我们能否找到索引的创建时间?最后一次索引重建(Index Rebuild)的时间? 最后一次索引重组(INDEX REORGANIZE)的时间呢?  答案是我们无法准确的找到 ...

  2. ORACLE11g下如何利用SQL DEVELOPER连接上数据库

    最近在学习数据库的相关内容,在sqlplus敲了几天命令行窗口后,想尝试一下用sql developer 连接上数据库但一直没有实现.在网上查询了相关资料后现在终于弄好了,就来写下此篇博文与大家分享! ...

  3. PL/SQL Developer下设置“长SQL自己主动换行”

    ***********************************************声明*************************************************** ...

  4. mybatis的sql中使用$会出现sql注入示例

    mybatis的sql中使用$会出现sql注入示例: 模拟简单登录场景: 页面代码: function login(){ //sql注入 var user = { username : "' ...

  5. SQL Server 执行计划利用统计信息对数据行的预估原理以及SQL Server 2014中预估策略的改变

    前提  本文仅讨论SQL Server查询时, 对于非复合统计信息,也即每个字段的统计信息只包含当前列的数据分布的情况下, 在用多个字段进行组合查询的时候,如何根据统计信息去预估行数的. 利用不同字段 ...

  6. 利用sql server直接创建日历

    看到网上有高手直接用sql查询创建日历,也想自己动手实践一遍.笔者这里的实现和网上的都没有什么区别,思路也没有什么新意.觉得好玩,就把它记下来吧. 一.准备知识1.sql的with关键字关于with和 ...

  7. 利用本地SQL Server维护计划来维护SQL Database

    On-Premise的SQL Server提供了维护计划来定期.定时的维护SQL Server.一般的做法是:定义SQL Server Agent Jobs,而后维护计划帮助我们定期.定时执行SQL ...

  8. 利用SQL Server 2008 R2创建自动备份计划

    本文主要利用SQL Server 2008 R2自带的"维护计划"创建一个自动备份数据的任务. 首先,启动 Sql Management studio,确保"SQL Se ...

  9. 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问题描述 ...

随机推荐

  1. 玩耍Hibernate系列(一)--基础知识

    Hibernate框架介绍: Hibernate  ORM  主要用于持久化对象(最常用的框架) Hibernate  Search 用于对对象进行搜索,底层基于Apache Lucene做的 Hib ...

  2. LabView调用C#混合模式dll

    在一些特定要求下,我们的C#可能需要制作dll给LabView进行调用,并且我们不能够保证C#的程序是完全自己写而不调用第三方的dll库.很多时候我们需要使用诸如Sqlite.Net.AForge.N ...

  3. Netsharp快速入门(之19) 平台常用功能(插件操作)

    作者:秋时 暗影  转载须说明出处 6.2     插件操作 6.2.1  停用/启用 1.在平台工具-插件管理,右击对应的插件可以使用启用和停用功能.插件停用后会把所有相关的页签.程序集.服务全部停 ...

  4. 【BZOJ】【2661】【Beijing WC2012】连连看

    网络流/费用流/二分图最大权匹配 拆点费用流求最大权匹配……为什么我拿zyf和Hzwer的代码也交不过去……WA了那么多次……so sad 求路过的神牛指导啊>_<万分感谢 //BZOJ ...

  5. jquery ajax/post/get 传参数给 mvc的action

    jquery ajax/post/get 传参数给 mvc的action1.ActionResult Test1    2.View  Test1.aspx3.ajax page4.MetaObjec ...

  6. POJ 3258 River Hopscotch (binarysearch)

    River Hopscotch Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 5193 Accepted: 2260 Descr ...

  7. slot的含义

    1) slot就是槽的意思,是一个资源单位,只有给task分配了一个slot之后,这个task才可以运行.slot分两种,map slot沪蓉reduce slot.另外,slot是一个逻辑概念,一个 ...

  8. 7 天玩转 ASP.NET MVC — 第 4 天

    目录 第 1 天 第 2 天 第 3 天 第 4 天 第 5 天 第 6 天 第 7 天 0. 前言 欢迎来到第四天的 MVC 系列学习中.如果你直接开始学习今天的课程,我强烈建议你先完成之前的学习内 ...

  9. cf div2 238 D

    D. Toy Sum time limit per test 1 second memory limit per test 256 megabytes input standard input out ...

  10. poj 1568 Find the Winning Move 极大极小搜索

    思路:用极大极小搜索解决这样的问题很方便!! 代码如下: #include <cstdio> #include <algorithm> #define inf 10000000 ...