В данном вебинаре я расскажу о том, что такое индексы, зачем они нужны, какие регламентные операции необходимо выполнять с индексами, а также будут приведены соответствующие скрипты (для MS SQL-Server) для обслуживания индексов баз данных.
Видео в формате вебинара с подробным разбором всех скриптов:
Все переменные в скриптах собраны в соответствующем блоке в начале скриптов. Для отправки электронной почты используется предварительно настроенный профиль электронной почты компоненты DataBase Mail. О настройке компоненты можно прочитать, здесь. Все скрипты много раз опробованы в бою и протестированы на версиях MS SQL 2008, 2012, 2016.
Может случиться так, что в процессе установки MS SQL Server 2012 были установлены компоненты, необходимость в которых со временем отпала (или были установлены по ошибке). В этом случае, в целях…
В данной статье будут рассмотрены способы лицензирования Microsoft SQL Server 2012. Будет приведен краткий обзор каждого из способов лицензирования, а также указаны возможные варианты лицензирования для различных выпусков MS SQL Server…
Ниже приводится список существующих редакций Microsoft SQL Server 2012, а также приводится краткий обзор каждой из них. Microsoft SQL Server 2012 предлагается в нескольких специально разработанных редакциях:…
Спасибо за уроки. Времени читать тягомотину на сайте MS нет, а здесь коротко, наглядно. Да еще и с конкретными примерами. Правда в репозитарий не могу попасть — пустой экран по ссылке.
Здравствуйте. После выполнения вашего скрипта (Обслуживание_индексов_БД.sql) (да и не только вашего скрипта, просто он показал ошибку) на одной из баз получаю сообщение:
Msg 1943, Level 16, State 1, Line 1
The index «_SystemSettings_1» on table «_SystemSettings» cannot be reorganized because page level locking is disabled.
В общем не удалось обслуживание. Что-то с таблицей.
Сталкивались с таким ? Что посоветуете?
Важно! Начиная с версии платформы 8.3.22 необходимо выполнять дефрагментацию индексов по следующему алгоритму:
До дефрагментации индекса необходимо включить страничные блокировки. Пример команды: ALTER INDEX index_name ON table_name SET (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON);
Выполнить дефрагментацию.
Обратно выключить страничные блокировки. Пример команды: ALTER INDEX index_name ON table_name SET (ALLOW_PAGE_LOCKS = OFF, ALLOW_ROW_LOCKS = ON);
Но как это правильно сделать в скрипте тоже не понимаю.
USE [ИмяБазы]
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = ON)’
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_ROW_LOCKS= ON)’
GO
после реорганизации
USE [ИмяБазы]
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = OFF)’
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_ROW_LOCKS= ON)’
GO
Можно оптимизировать и не делать 2 цикла!
Соответствтенно до реорганизации:
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS= ON)’
После:
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = OFF, ALLOW_ROW_LOCKS= ON)’
привет. переделал немного ваш скрипт. включил блокировки страниц(без этого — ошибка на базе 1с). кривовато получилось, но работает. 13сек делает 8.5гб базу. Можете помочь с корректным прописанием условия? чтобы если у индекса отключены блокировки страниц — запускать команды @command1 и @cammand2. Если и без них включены — не запускать. Иначе, мой скрипт будет уродовать базы, отключая блокировки там, где они были изначально включены. Скрипт:
USE [1]
——————————————-
— СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ
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 для дефрагментации либо ренидексации
DECLARE @command1 nvarchar(4000); — инструкция T-SQL для дефрагментации либо ренидексации
DECLARE @command2 nvarchar(4000); — инструкция T-SQL для дефрагментации либо ренидексации
——————————————-
— ТЕЛО СКРИПТА
— Отключаем вывод количества возвращаемых строк, это несколько ускорит обработку
SET NOCOUNT ON;
— Удалим временные таблицы, если вдруг они есть
IF OBJECT_ID(‘tempdb.dbo.#work_to_do’) IS NOT NULL DROP TABLE #work_to_do
— Отбор таблиц и индексов с помощью системного представления 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’ REBUILD WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, SORT_IN_TEMPDB = ON, ONLINE = ON, maxdop = 8 )’;
IF @partition_number > 1
SET @command = @command + N’ PARTITION=’ + CAST(@partition_number AS nvarchar(10));
—В первом сообщении не полностью вставился скрипт((
Привет. переделал немного ваш скрипт. включил блокировки страниц(без этого — ошибка на базе 1с). кривовато получилось, но работает. 13сек делает 8.5гб базу. Можете помочь с корректным прописанием условия? чтобы если у индекса отключены блокировки страниц — запускать команды @command1 и @cammand2. Если и без них включены — не запускать. Иначе, мой скрипт будет уродовать базы, отключая блокировки там, где они были изначально включены. Скрипт:
USE [1]
——————————————-
— СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ
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 для дефрагментации либо ренидексации
DECLARE @command1 nvarchar(4000); — инструкция T-SQL для дефрагментации либо ренидексации
DECLARE @command2 nvarchar(4000); — инструкция T-SQL для дефрагментации либо ренидексации
——————————————-
— ТЕЛО СКРИПТА
— Отключаем вывод количества возвращаемых строк, это несколько ускорит обработку
SET NOCOUNT ON;
— Удалим временные таблицы, если вдруг они есть
IF OBJECT_ID(‘tempdb.dbo.#work_to_do’) IS NOT NULL DROP TABLE #work_to_do
— Отбор таблиц и индексов с помощью системного представления 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’ REBUILD WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, SORT_IN_TEMPDB = ON, ONLINE = ON, maxdop = 8 )’;
IF @partition_number > 1
SET @command = @command + N’ PARTITION=’ + CAST(@partition_number AS nvarchar(10));
—да что за фигня то)) вот кусок недостающего кода
— Если фрагментация менее или равна 30% тогда дефрагментация, иначе реиндексация
IF @fragmentation_in_percent = 30.0
—перестроение индекса
SET @command = N’ALTER INDEX ‘ + @indexname + N’ ON ‘ + @schemaname + N’.’ + @objectname + N’ REBUILD WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, SORT_IN_TEMPDB = ON, ONLINE = ON, maxdop = 8 )’;
IF @partition_number > 1
SET @command = @command + N’ PARTITION=’ + CAST(@partition_number AS nvarchar(10));
Спасибо за уроки. Времени читать тягомотину на сайте MS нет, а здесь коротко, наглядно. Да еще и с конкретными примерами. Правда в репозитарий не могу попасть — пустой экран по ссылке.
Спасибо за отзыв.
По поводу ссылки, очень странно, пробовал с разных устройств, у меня проблем нет. Попробуйте зайти через мой профиль: https://github.com/Tavalik
Здравствуйте. После выполнения вашего скрипта (Обслуживание_индексов_БД.sql) (да и не только вашего скрипта, просто он показал ошибку) на одной из баз получаю сообщение:
Msg 1943, Level 16, State 1, Line 1
The index «_SystemSettings_1» on table «_SystemSettings» cannot be reorganized because page level locking is disabled.
В общем не удалось обслуживание. Что-то с таблицей.
Сталкивались с таким ? Что посоветуете?
Вот причина: https://its.1c.ru/db/metod8dev#content:5837:hdoc:p3
Важно! Начиная с версии платформы 8.3.22 необходимо выполнять дефрагментацию индексов по следующему алгоритму:
До дефрагментации индекса необходимо включить страничные блокировки. Пример команды: ALTER INDEX index_name ON table_name SET (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON);
Выполнить дефрагментацию.
Обратно выключить страничные блокировки. Пример команды: ALTER INDEX index_name ON table_name SET (ALLOW_PAGE_LOCKS = OFF, ALLOW_ROW_LOCKS = ON);
Но как это правильно сделать в скрипте тоже не понимаю.
USE [ИмяБазы]
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = ON)’
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_ROW_LOCKS= ON)’
GO
после реорганизации
USE [ИмяБазы]
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = OFF)’
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_ROW_LOCKS= ON)’
GO
спс
Можно оптимизировать и не делать 2 цикла!
Соответствтенно до реорганизации:
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS= ON)’
После:
EXEC sp_MSforeachtable ‘ALTER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = OFF, ALLOW_ROW_LOCKS= ON)’
привет. переделал немного ваш скрипт. включил блокировки страниц(без этого — ошибка на базе 1с). кривовато получилось, но работает. 13сек делает 8.5гб базу. Можете помочь с корректным прописанием условия? чтобы если у индекса отключены блокировки страниц — запускать команды @command1 и @cammand2. Если и без них включены — не запускать. Иначе, мой скрипт будет уродовать базы, отключая блокировки там, где они были изначально включены. Скрипт:
USE [1]
——————————————-
— СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ
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 для дефрагментации либо ренидексации
DECLARE @command1 nvarchar(4000); — инструкция T-SQL для дефрагментации либо ренидексации
DECLARE @command2 nvarchar(4000); — инструкция T-SQL для дефрагментации либо ренидексации
——————————————-
— ТЕЛО СКРИПТА
— Отключаем вывод количества возвращаемых строк, это несколько ускорит обработку
SET NOCOUNT ON;
— Удалим временные таблицы, если вдруг они есть
IF OBJECT_ID(‘tempdb.dbo.#work_to_do’) IS NOT NULL DROP TABLE #work_to_do
— Отбор таблиц и индексов с помощью системного представления 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’ REBUILD WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, SORT_IN_TEMPDB = ON, ONLINE = ON, maxdop = 8 )’;
IF @partition_number > 1
SET @command = @command + N’ PARTITION=’ + CAST(@partition_number AS nvarchar(10));
— Выполняем команду
EXEC (@command1);
EXEC (@command);
EXEC (@command2);
PRINT N’Index: object_id=’ + STR(@object_id) + ‘, index_id=’ + STR(@index_id) + ‘, fragmentation_in_percent=’ + STR(@fragmentation_in_percent);
PRINT N’Executed: ‘ + @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;
GO
—В первом сообщении не полностью вставился скрипт((
Привет. переделал немного ваш скрипт. включил блокировки страниц(без этого — ошибка на базе 1с). кривовато получилось, но работает. 13сек делает 8.5гб базу. Можете помочь с корректным прописанием условия? чтобы если у индекса отключены блокировки страниц — запускать команды @command1 и @cammand2. Если и без них включены — не запускать. Иначе, мой скрипт будет уродовать базы, отключая блокировки там, где они были изначально включены. Скрипт:
USE [1]
——————————————-
— СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ
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 для дефрагментации либо ренидексации
DECLARE @command1 nvarchar(4000); — инструкция T-SQL для дефрагментации либо ренидексации
DECLARE @command2 nvarchar(4000); — инструкция T-SQL для дефрагментации либо ренидексации
——————————————-
— ТЕЛО СКРИПТА
— Отключаем вывод количества возвращаемых строк, это несколько ускорит обработку
SET NOCOUNT ON;
— Удалим временные таблицы, если вдруг они есть
IF OBJECT_ID(‘tempdb.dbo.#work_to_do’) IS NOT NULL DROP TABLE #work_to_do
— Отбор таблиц и индексов с помощью системного представления 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’ REBUILD WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, SORT_IN_TEMPDB = ON, ONLINE = ON, maxdop = 8 )’;
IF @partition_number > 1
SET @command = @command + N’ PARTITION=’ + CAST(@partition_number AS nvarchar(10));
— Выполняем команду
EXEC (@command1);
EXEC (@command);
EXEC (@command2);
PRINT N’Index: object_id=’ + STR(@object_id) + ‘, index_id=’ + STR(@index_id) + ‘, fragmentation_in_percent=’ + STR(@fragmentation_in_percent);
PRINT N’Executed: ‘ + @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;
GO
—да что за фигня то)) вот кусок недостающего кода
— Если фрагментация менее или равна 30% тогда дефрагментация, иначе реиндексация
IF @fragmentation_in_percent = 30.0
—перестроение индекса
SET @command = N’ALTER INDEX ‘ + @indexname + N’ ON ‘ + @schemaname + N’.’ + @objectname + N’ REBUILD WITH (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON, SORT_IN_TEMPDB = ON, ONLINE = ON, maxdop = 8 )’;
IF @partition_number > 1
SET @command = @command + N’ PARTITION=’ + CAST(@partition_number AS nvarchar(10));
— Выполняем команду
EXEC (@command1);
EXEC (@command);
EXEC (@command2);
PRINT N’Index: object_id=’ + STR(@object_id) + ‘, index_id=’ + STR(@index_id) + ‘, fragmentation_in_percent=’ + STR(@fragmentation_in_percent);
PRINT N’Executed: ‘ + @command;
—какая-то фигня с сайтом. не знаю почему не вставлят несколько строчек. похоже, считает вредоносным кодом(
— Если фрагментация менее или равна 30% тогда дефрагментация, иначе реиндексация
IF @fragmentation_in_percent = 30.0
—перестроение индекса
Вот тут сделал тему про оптимизацию вашего скрипта. Все получилось, но комментарии и помощь приветствуются!
http://www.gilev.ru/forum/viewtopic.php?f=15&t=2012&p=8603#p8603