forked from Tavalik/SQL_TScripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Обслуживание_индексов_нескольких_БД.sql
178 lines (152 loc) · 8.24 KB
/
Обслуживание_индексов_нескольких_БД.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
-------------------------------------------
-- Скрипт выполняет реорганизацию либо дефрагменатцию индексов баз данных
-- Алгоритм работы:
-- 1. Отбираются базы данных по задаваемому условнию
-- 2. Для каждой из баз данных:
-- 2.1. Собираются информация обо всех фрагментированных индексах (степерь фрагментации более 5%)
-- 2.2. Если фрагментация менее или равна 30% тогда выполняется дефрагментация, иначе реиндексация индекса
-- 3. Отправляется электронное сообщение о результате работы с использованием настроенного почтового профиля
-- Автор: Онянов Виталий (Tavalik.ru)
-- Версия от 09.08.2017
-- Свежие версии скриптов: https://github.com/Tavalik/SQL_TScripts
---------------------------------------------
-- НАСТРАИВАЕМЫЕ ПАРАМЕТРЫ
-- Условие для выборки, '%' - все базы данных
DECLARE @namelike varchar(100) = 'WorkBase%'
-- Имя почтового профиля, для отправки электонной почты
DECLARE @profilename as nvarchar(100) = 'ОсновнойПрофиль'
-- Получатели сообщений электронной почты, разделенные знаком ";"
DECLARE @recipients as nvarchar(500) = '[email protected]'
-------------------------------------------
-- СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ
DECLARE @database_id varchar(100) -- ID баз данных
DECLARE @database_name varchar(100) -- Имена баз данных
DECLARE @command nvarchar(4000); -- инструкция T-SQL для дефрагментации либо ренидексации
DECLARE @subject as NVARCHAR(1000) = '' -- тема сообщения
DECLARE @finalmassage as NVARCHAR(4000) = '' -- текст сообщения
-------------------------------------------
-- ТЕЛО СКРИПТА
USE master
-- Отключаем вывод количества возвращаемых строк, это несколько ускорит обработку
SET NOCOUNT ON;
-- Выбираем базы данных
DECLARE DBcursor CURSOR FOR
(
SELECT
database_id as database_id,
name as database_name
FROM sys.databases d
WHERE
d.name <> 'tempdb'
AND d.name <> 'master'
AND d.name <> 'model'
AND d.name <> 'msdb'
AND d.state_desc = 'ONLINE' -- база должна быть в сети
AND d.name like @namelike -- база должна содержать указанное слово
)
-- Цикл по всем базам, попавшим в выборку
OPEN DBcursor
FETCH NEXT FROM DBcursor INTO @database_id, @database_name
WHILE @@FETCH_STATUS = 0
BEGIN
-- База данных из цикла
PRINT N'----------------------------------------------------------'
PRINT N'USE [' + @database_name + N']'
SET @command =
N'USE [' + @database_name + N']
DECLARE @object_id int; -- ID объекта
DECLARE @index_id int; -- ID индекса
DECLARE @partition_number bigint; -- количество секций если индекс секционирован
DECLARE @schemaname nvarchar(130); -- имя схемы в которой находится таблица
DECLARE @objectname nvarchar(130); -- имя таблицы
DECLARE @indexname nvarchar(130); -- имя индекса
DECLARE @partitionnum bigint; -- номер секции
DECLARE @fragmentation_in_percent float; -- процент фрагментации индекса
DECLARE @command nvarchar(4000); -- инструкция T-SQL для дефрагментации либо ренидексации
-- Отбор таблиц и индексов с помощью системного представления sys.dm_db_index_physical_stats
-- Отбор только тех объектов которые:
-- являются индексами (index_id > 0)
-- фрагментация которых более 5%
-- количество страниц в индексе более 128
SELECT
object_id,
index_id,
partition_number,
avg_fragmentation_in_percent AS fragmentation_in_percent
INTO #work_to_do
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, ''LIMITED'')
WHERE index_id > 0
AND avg_fragmentation_in_percent > 5.0
AND page_count > 128;
-- Объявление Открытие курсора курсора для чтения секций
DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do;
OPEN partitions;
-- Цикл по секциям
FETCH NEXT FROM partitions INTO @object_id, @index_id, @partition_number, @fragmentation_in_percent;
WHILE @@FETCH_STATUS = 0
BEGIN
-- Собираем имена объектов по ID
SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name)
FROM sys.objects AS o
JOIN sys.schemas as s ON s.schema_id = o.schema_id
WHERE o.object_id = @object_id;
SELECT @indexname = QUOTENAME(name)
FROM sys.indexes
WHERE object_id = @object_id AND index_id = @index_id;
SELECT @partition_number = count (*)
FROM sys.partitions
WHERE object_id = @object_id AND index_id = @index_id;
-- Если фрагментация менее или равна 30% тогда дефрагментация, иначе реиндексация
IF @fragmentation_in_percent < 30.0
SET @command = N''ALTER INDEX '' + @indexname + N'' ON '' + @schemaname + N''.'' + @objectname + N'' REORGANIZE'';
IF @fragmentation_in_percent >= 30.0
SET @command = N''ALTER INDEX '' + @indexname + N'' ON '' + @schemaname + N''.'' + @objectname + N'' REBUILD'';
IF @partition_number > 1
SET @command = @command + N'' PARTITION='' + CAST(@partition_number AS nvarchar(10));
-- Выполняем команду
PRINT N'' Executed: '' + @command;
EXEC sp_executesql @command
-- Следующий элемент цикла
FETCH NEXT FROM partitions INTO @object_id, @index_id, @partition_number, @fragmentation_in_percent;
END;
-- Закрытие курсора
CLOSE partitions;
DEALLOCATE partitions;
-- Удаление временной таблицы
DROP TABLE #work_to_do;';
BEGIN TRY
EXEC sp_executesql @command
SET @finalmassage = @finalmassage + 'Успешное выполнение операций обслуживания индексов для базы данных ' + @database_name + CHAR(13) + CHAR(13)
END TRY
BEGIN CATCH
-- Ошбика выполнения операции
SET @subject = 'БЫЛИ ОШИБКИ при выполнении операций обслуживания индексов '
SET @finalmassage = @finalmassage + 'ОШИБКА обслуживания индекса для базы данных ' + @database_name + CHAR(13) + CHAR(13)
+ 'Код ошибки: ' + CAST(ERROR_NUMBER() as nvarchar(10)) + CHAR(13) + CHAR(13)
+ 'Текст ошибки: ' + ERROR_MESSAGE() + CHAR(13) + CHAR(13)
+ 'Текст T-SQL: ' + CHAR(13) + @command + CHAR(13) + CHAR(13)
END CATCH;
-- Следующая база данных
FETCH NEXT FROM DBcursor INTO @database_id, @database_name
END;
CLOSE DBcursor;
DEALLOCATE DBcursor;
-- Формируем сообщение об успешном или не успешном выполнении операций
IF @subject = ''
BEGIN
-- Успешное выполнение всех операций
SET @subject = 'Успешное выполнение операций обслуживания индексов '
END
-- Если задан профиль электронной почты, отправим сообщение
PRINT N'----------------------------------------------------------'
IF @profilename <> ''
EXEC msdb.dbo.sp_send_dbmail
@profile_name = @profilename,
@recipients = @recipients,
@body = @finalmassage,
@subject = @subject;
-- Выводим сообщение о результате
SELECT
@subject as subject,
@finalmassage as finalmassage
GO