|
MS SQL Долго выполняется реорганизация индекса. Куда смотреть? H A D G E H O G s, vis, Crusher, arsik, Neo58, AlexKimp, АНДР, 1cVandal, nextssbt, Fedor-1971, Dedal, Dmitrii, Кир Пластелинин, Ботаник Гарден Меран, Бертыш, Михаил Козлов, breezee, Krendel, shuhard, X Leshiy, proger2021, ADirks, JohnGilbert, Злопчинский, okmail, lordworld17, oleg_km, RAJAH, Vstur, Мультук, Fragster, DemonShinji2, kir-g, maxab72, Сукпун, phabeZ, Lama12, trad, ivanov-i-i, Hawk_1c, unenu, diamkms, _Batoo, Seducer, alexxx961503, alexela, zenik, Double_Medved, Доминошник, Amra, trk415e76, vbus, msm1981, Zamestas, Timon1405, elka302, NikeArz, Шурик71, serpentt
| ☑ | ||
|---|---|---|---|---|
|
0
arsik
гуру
06.07.26
✎
09:30
|
MS SQL 2022
В плане обслуживания несколько задач 1) Включить страничные блокировки (EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = ON)' ) 2) Реорганизация индекса (см. скриншот) 3) Выключить страничные блокировки (EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = OFF)' ) 4) Обновление статистики 5) очистка кеша (dbcc freeproccache) 6) Сброс статистики ожидания (DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR)) Судя по журналу - Продолжительность самой реорганизации - 11 минут, но делается это 7 часов.
|
|||
|
1
Lama12
06.07.26
✎
09:08
|
скриншота нет
|
|||
|
2
arsik
гуру
06.07.26
✎
09:33
|
(1) Сорян. Добавил.
+(0) Базы небольшие - 3 бухгалтерии общим объемом (37 Гб - .mdf) - 3 камина (15 Гб - .mdf) - 1 альфа авто 6 (9 Гб - .mdf) |
|||
|
3
arsik
гуру
06.07.26
✎
09:40
|
Если я правильно понял, скуль долго подготавливает tsql скрипт для реорганизации.
Т.к. пробовал посмотреть T-SQL в реорганизации - не дождался. Именно это время я думаю занимает 7 часов.
|
|||
|
4
arsik
гуру
06.07.26
✎
09:42
|
Ну и еще нюанс. Служба агента и служба скуля запускаються от учетной записи MSA пользователя домена на этом сервере. Может тут проблема?
|
|||
|
5
Lama12
06.07.26
✎
09:48
|
(4) Это вряд ли.
|
|||
|
6
Fedor-1971
06.07.26
✎
10:05
|
(3) Чисто предположение: может долго определяется % фрагментации? типа нужно обновить статистику БД, а потом отправлять в реиндекс?
Можно попробовать тупо Reindex всей БД. На сколько знаю, есть скрипт, тупой переиндексации самых больших таблиц БД с какой-то периодичностью, но это тема для конфигураций уровня ЕРП |
|||
|
7
arsik
гуру
06.07.26
✎
10:50
|
(6) Ну мне ИИ сделал готовый скрипт конечно. Но я хотел разобраться в проблеме.
PS: Вот поправленный скрипт, с включением блокировки перед реорганизацией и выключением после /*
=============================================================================
Скрипт обслуживания индексов (Index Maintenance)
Требования: SQL Server 2016 и выше (используется STRING_SPLIT)
ВАЖНО: Для операции REORGANIZE скрипт временно включает ALLOW_PAGE_LOCKS = ON,
а после завершения возвращает ALLOW_PAGE_LOCKS = OFF.
Убедитесь, что это соответствует требованиям вашей нагрузки!
=============================================================================
*/
-- ==================== ПАРАМЕТРЫ ====================
-- 1. Список баз данных через запятую
DECLARE @DatabaseList NVARCHAR(MAX) = N'Database1, Database2, Database3';
-- 2. Пороги фрагментации (согласно вашему ТЗ)
DECLARE @ThresholdReorganize FLOAT = 5.0; -- Менее 5% - ничего не делаем
DECLARE @ThresholdRebuild FLOAT = 30.0; -- Более 30% - перестроение (REBUILD)
-- 3. Дополнительные рекомендуемые параметры
DECLARE @MinPageCount INT = 1000; -- Игнорировать индексы меньше 1000 страниц (8 МБ)
DECLARE @OnlineRebuild BIT = 0; -- 1 = ONLINE = ON (требует Enterprise/Developer edition)
DECLARE @ReportOnly BIT = 1; -- 1 = только отчет, 0 = выполнять
-- ==================== ЛОГИКА СКРИПТА ====================
IF @ReportOnly = 1
PRINT N'*** РЕЖИМ ТОЛЬКО ОТЧЕТ - команды не будут выполнены ***';
ELSE
PRINT N'*** РАБОЧИЙ РЕЖИМ - команды будут выполнены ***';
-- Таблица для хранения списка индексов, требующих обслуживания
DECLARE @IndexesToMaintain TABLE (
DBName NVARCHAR(128),
SchemaName NVARCHAR(128),
TableName NVARCHAR(128),
IndexName NVARCHAR(128),
FragPercent FLOAT,
Action NVARCHAR(20),
OriginalPageLocks BIT, -- Исходное состояние ALLOW_PAGE_LOCKS
SqlCommand NVARCHAR(MAX)
);
-- Сбор информации о фрагментации
PRINT N'Анализ фрагментации индексов...';
INSERT INTO @IndexesToMaintain (DBName, SchemaName, TableName, IndexName, FragPercent, Action, OriginalPageLocks, SqlCommand)
SELECT
DB_NAME(ps.database_id) AS DBName,
s.name AS SchemaName,
t.name AS TableName,
i.name AS IndexName,
ps.avg_fragmentation_in_percent,
CASE
WHEN ps.avg_fragmentation_in_percent <= @ThresholdRebuild THEN 'REORGANIZE'
ELSE 'REBUILD'
END AS Action,
i.allow_page_locks AS OriginalPageLocks,
CASE
WHEN ps.avg_fragmentation_in_percent <= @ThresholdRebuild
THEN N'-- Включаем блокировки на уровне страницы
ALTER INDEX ' + QUOTENAME(i.name) + N' ON ' +
QUOTENAME(DB_NAME(ps.database_id)) + N'.' + QUOTENAME(s.name) + N'.' + QUOTENAME(t.name) +
N' SET (ALLOW_PAGE_LOCKS = ON);
-- Реорганизация индекса
ALTER INDEX ' + QUOTENAME(i.name) + N' ON ' +
QUOTENAME(DB_NAME(ps.database_id)) + N'.' + QUOTENAME(s.name) + N'.' + QUOTENAME(t.name) +
N' REORGANIZE;
-- Выключаем блокировки на уровне страницы
ALTER INDEX ' + QUOTENAME(i.name) + N' ON ' +
QUOTENAME(DB_NAME(ps.database_id)) + N'.' + QUOTENAME(s.name) + N'.' + QUOTENAME(t.name) +
N' SET (ALLOW_PAGE_LOCKS = OFF);'
ELSE N'ALTER INDEX ' + QUOTENAME(i.name) + N' ON ' +
QUOTENAME(DB_NAME(ps.database_id)) + N'.' + QUOTENAME(s.name) + N'.' + QUOTENAME(t.name) +
N' REBUILD' +
CASE WHEN @OnlineRebuild = 1 THEN N' WITH (ONLINE = ON)' ELSE N'' END +
N';'
END AS SqlCommand
FROM sys.dm_db_index_physical_stats(NULL, NULL, NULL, NULL, 'LIMITED') ps
INNER JOIN sys.databases d ON ps.database_id = d.database_id
INNER JOIN sys.tables t ON ps.object_id = t.object_id
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN sys.indexes i ON ps.object_id = i.object_id AND ps.index_id = i.index_id
WHERE d.name IN (SELECT LTRIM(RTRIM(value)) FROM STRING_SPLIT(@DatabaseList, ','))
AND d.state = 0 -- Только ONLINE базы
AND d.is_read_only = 0 -- Исключаем Read-Only базы
AND ps.avg_fragmentation_in_percent > @ThresholdReorganize -- Фильтр: < 5% не берем
AND i.type IN (1, 2) -- 1 = Clustered, 2 = NonClustered
AND i.is_disabled = 0 -- Исключаем отключенные индексы
AND ps.page_count >= @MinPageCount; -- Исключаем очень маленькие таблицы
DECLARE @IndexCount INT = @@ROWCOUNT;
PRINT N'Найдено индексов для обслуживания: ' + CAST(@IndexCount AS NVARCHAR(10));
PRINT N'';
-- ==================== ВЫВОД ОТЧЕТА ====================
IF @ReportOnly = 1
BEGIN
-- Выводим детальную таблицу с командами
SELECT
DBName AS [База данных],
SchemaName + '.' + TableName AS [Таблица],
IndexName AS [Индекс],
CAST(FragPercent AS DECIMAL(5,2)) AS [Фрагментация %],
Action AS [Действие],
CASE
WHEN Action = 'REORGANIZE' THEN
CASE WHEN OriginalPageLocks = 1 THEN 'Да (было ON)' ELSE 'Нет (было OFF)' END
ELSE 'N/A'
END AS [Исходные Page Locks],
SqlCommand AS [SQL команды]
FROM @IndexesToMaintain
ORDER BY FragPercent DESC;
PRINT N'';
PRINT N'===================================================';
PRINT N'Отчет сформирован. Команды не выполнены.';
PRINT N'Для выполнения обслуживания установите @ReportOnly = 0';
END
ELSE
BEGIN
-- Рабочий режим: выполняем команды
DECLARE @db NVARCHAR(128), @sch NVARCHAR(128), @tbl NVARCHAR(128), @idx NVARCHAR(128);
DECLARE @frag FLOAT, @sql NVARCHAR(MAX), @action NVARCHAR(20);
DECLARE @originalPageLocks BIT;
DECLARE cur CURSOR LOCAL FAST_FORWARD FOR
SELECT DBName, SchemaName, TableName, IndexName, FragPercent, Action, SqlCommand, OriginalPageLocks
FROM @IndexesToMaintain
ORDER BY FragPercent DESC;
OPEN cur;
FETCH NEXT FROM cur INTO @db, @sch, @tbl, @idx, @frag, @action, @sql, @originalPageLocks;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT N'---------------------------------------------------';
PRINT N'База: ' + @db + N' | Таблица: ' + @sch + N'.' + @tbl + N' | Индекс: ' + @idx;
PRINT N'Фрагментация: ' + CAST(@frag AS NVARCHAR(10)) + N'% | Действие: ' + @action;
IF @action = 'REORGANIZE'
BEGIN
PRINT N'Исходное состояние ALLOW_PAGE_LOCKS: ' +
CASE WHEN @originalPageLocks = 1 THEN 'ON' ELSE 'OFF' END;
END
BEGIN TRY
-- Выполняем команды последовательно
IF @action = 'REORGANIZE'
BEGIN
-- Команда 1: Включить ALLOW_PAGE_LOCKS
DECLARE @sqlEnableLocks NVARCHAR(MAX) =
N'ALTER INDEX ' + QUOTENAME(@idx) + N' ON ' +
QUOTENAME(@db) + N'.' + QUOTENAME(@sch) + N'.' + QUOTENAME(@tbl) +
N' SET (ALLOW_PAGE_LOCKS = ON);';
PRINT N' [1/3] Включаю ALLOW_PAGE_LOCKS = ON...';
EXEC sp_executesql @sqlEnableLocks;
-- Команда 2: Реорганизация
DECLARE @sqlReorganize NVARCHAR(MAX) =
N'ALTER INDEX ' + QUOTENAME(@idx) + N' ON ' +
QUOTENAME(@db) + N'.' + QUOTENAME(@sch) + N'.' + QUOTENAME(@tbl) +
N' REORGANIZE;';
PRINT N' [2/3] Выполняю REORGANIZE...';
EXEC sp_executesql @sqlReorganize;
-- Команда 3: Выключить ALLOW_PAGE_LOCKS
DECLARE @sqlDisableLocks NVARCHAR(MAX) =
N'ALTER INDEX ' + QUOTENAME(@idx) + N' ON ' +
QUOTENAME(@db) + N'.' + QUOTENAME(@sch) + N'.' + QUOTENAME(@tbl) +
N' SET (ALLOW_PAGE_LOCKS = OFF);';
PRINT N' [3/3] Выключаю ALLOW_PAGE_LOCKS = OFF...';
EXEC sp_executesql @sqlDisableLocks;
END
ELSE
BEGIN
-- Для REBUILD выполняем одну команду
PRINT N' Выполняю REBUILD...';
EXEC sp_executesql @sql;
END
PRINT N'Успешно выполнено.';
END TRY
BEGIN CATCH
PRINT N'ОШИБКА при выполнении: ' + ERROR_MESSAGE();
END CATCH
FETCH NEXT FROM cur INTO @db, @sch, @tbl, @idx, @frag, @action, @sql, @originalPageLocks;
END
CLOSE cur;
DEALLOCATE cur;
PRINT N'';
PRINT N'===================================================';
PRINT N'Обслуживание индексов завершено.';
END |
|||
|
8
proger2021
06.07.26
✎
10:53
|
(3) Похоже на ожидание на блокировке, возможно на какойнить системной таблице. Попробуйте запустить еще раз и посмотреть блокировки в мониторе активности.
|
|||
|
9
arsik
гуру
06.07.26
✎
11:34
|
(8) Запустил по одной базе. Что то там шуршит, но в мониторе никаких блокировок.
|
|||
|
10
arsik
гуру
06.07.26
✎
13:37
|
Попробовал разное, но никаких изменений.
Для 1й базы задание выполнялось 2 часа. Пробовал перед запуском задания обновить статистику - без результатно. Из монитора активности скачал план выполнения - итить колотить 3 мегабайта. Ну нахер. |
|||
|
11
H A D G E H O G s
06.07.26
✎
13:48
|
(10) а вооон в том мегаскрипте нет случайно crossjoin во всех этих связях 5ти таблиц из за отсутствующего условия соединения?
|
| Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |