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

搞定

时间: 2024-08-28 17:30:08

SQL Server下实现利用SQL Server Agent Job对索引重建实现Balance Load的相关文章

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

原文:SQL Server中是否可以准确获取最后一次索引重建的时间? 在SQL Server中,我们能否找到索引的创建时间?最后一次索引重建(Index Rebuild)的时间? 最后一次索引重组(INDEX REORGANIZE)的时间呢?  答案是我们无法准确的找到索引的创建时间.最后一次索引重组时间,最后一次索引重建的时间. 其实就目前SQL Server的各个版本而言,还没有一个系统表或DMV视图有保存索引创建的时间,索引重建的时间.索引重组的时间.但是有些方法可以间接得到最后一次索引重

sql server 2008 之利用SQL Server Management Studio创建数据库(最基础)

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

最近在学习数据库的相关内容,在sqlplus敲了几天命令行窗口后,想尝试一下用sql developer 连接上数据库但一直没有实现.在网上查询了相关资料后现在终于弄好了,就来写下此篇博文与大家分享!接下来给大家分步骤介绍. 1.打开sql developer后配置java.exe路径.这点装过ecilipse的应该都很熟悉了,在此就不细说了.如果不记得自己java环境的安装路径推荐大家可以下载everything这款window下非常好用的文件搜索软件. 2.打开后我们就可以看到这样的界面.

PL/SQL Developer下设置“长SQL自动换行”

***********************************************声明***********************************************************************  原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong/article/details/39932149 *******

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

On-Premise的SQL Server提供了维护计划来定期.定时的维护SQL Server.一般的做法是:定义SQL Server Agent Jobs,而后维护计划帮助我们定期.定时执行SQL Server Agent Jobs.遗憾的是,SQL Database并不提供维护计划以及SQL Server Agent功能. 然而,根据MSDN的说法,我们依然可以通过SQL Server提供的维护计划连接到SQL Database.(Microsoft Azure SQL Database d

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

前提  本文仅讨论SQL Server查询时, 对于非复合统计信息,也即每个字段的统计信息只包含当前列的数据分布的情况下, 在用多个字段进行组合查询的时候,如何根据统计信息去预估行数的. 利用不同字段的统计信息做数据行数预估的算法原理,以及SQL Server 2012和SQL Server 2014该算法的差异情况, 这里暂时不涉及复合统计信息,暂不涉及统计信息的更新策略及优化相关话题,以及其他SQL Server版本计算方式. 统计信息是什么 简单说就是对某些字段的数据分布的一种描述,让SQ

Centos 7.3下 Linux For SQL Server安装及配置介绍

Centos 7.3下Linux For SQL Server安装及配置介绍 说到SQL Server服务,我们大家都知道是Microsoft公司的数据库服务,当然说到数据库,现在主要分为三大商:1:Oracle.2:Msql Server.3:Mysql:三种数据库在当下环境受到不了不同程度的关注:比如oracle主要应用到大型的商业比较多,比如银行:SQL Server主要在常见的互联网公司使用:mysql主要应用于小型的企业或者服务商使用:当然从费用上来说,Oracle是最贵的,也是最为稳

讲诉从酒店服务业到IT行业的心酸取经路,另附拙作 ASP.net(C#)利用SQL Server实现注册和登陆功能

楼主本人姓周,名XX,老家是曾国藩故居的,说起来和古人也算是邻里邻居. 92年出生,去年大专毕业,到现在毕业快要一年了,大学里学的专业是酒店管理,我们对外宣称为"第三产业"呵呵.到这里你们可能会心生疑问,咦,大学里怎么会有"酒店专业",你怎么会选它?说到这,楼主不得不提起一个人,那就是我的堂姐,楼主填志愿那年,人小不懂事,根本不知道如何去选择自己的专业,家里人就更不懂了,所以填志愿的事都在我这个堂姐手里做的主,填的那个学校是湖南长沙的,三年大专制,因为我这个表姐本人

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

本文主要利用SQL Server 2008 R2自带的"维护计划"创建一个自动备份数据的任务. 首先,启动?Sql Management studio,确保"SQL Server 代理"处于启动状态.如果没有,可以右击选择"启动". 第二步,依次展开"管理"---"维护计划",并右击"维护计划"选择"新建维护计划",这里你可以填写一个合适的有意义的名字. 点击&quo