Реорганизация индексов базы данных MS SQL "Невозможно реорганизовать индекс"

1. tekit 09.11.22 11:35 Сейчас в теме
Приветствую вас заклинатели железа, направляю вам преинтереснейшую ситуёвину для разбора и помощи вашему слуге.

Проблема: После обновления платформы 8.3.20.1674->8.3.22.1603 сломалось автоматическое резервное копирование баз данных, созданное менеджером в SSMS 2012. При попытке реиндексации баз данных коих у нас не одна, ssms ругается на "Невозможно реорганизовать индекс "_Acc48_1" в таблице "_Acc48", поскольку отключена блокировка на уровне страницы." И так на 30к+ индексов. Во всех базах где произошло какое-то обновление/регламентное задание/бог его знает что ещё. В кратце, для реиндексации нужно чтобы все таблицы баз были с включенным параметром "allow_page_locks" или как описан в клиенте он "Блокировка страниц в памяти".

Что пробовал?:
· Гуглил. Не помогло.
· Доставать dt сувать обратно, индексы логично достаются и суются вместе с базой. Не помогло.
· Поднимал бэкап до обновления платформы в тест базу, смотрел что в индексах с нашим параметром. Там везде "ON". У нас после обновы в 30к "OFF".
· В небольших базах было по 1-2 индекса с флагом офф, проставлял там руками параметр в истину, запускал план бэкапа, реиндексация и сам бэкап проходили на ура. Сделал вывод, что выставив как-то параметр в 30к индексах я таки получу автобэкапирование, но не пойму причины возникновения отключения параметра. Можно утолкать кусок скрипта перед реиндексацией который будет ставить параметр в "ON". Костыль....
· Пробовал делать тестирование и исправление ошибок через конфигуратор. Не помогло.

Люди добрые:
Кто сталкивался с подобным? Подскажите как решали.
Кто сможет написать запрос который в автомате проставит флаг во всех индексах всех таблиц базы, буду очень признателен.
Конструкция
ALT ER   INDEX ALL ON <Table name>
SET (ALLOW_PAGE_LOCKS = ON)
GO
не помогает, так как во втором параметре нужна таблица, как туда указать все таблицы, не знаю, не могу, не умею.
mafnitofon; onetone; arkitekt; user1795406; thunder367; +5 Ответить
Найденные решения
8. splxgf 09.11.22 16:35 Сейчас в теме
(1)
как туда указать все таблицы, не знаю

USE имя базы
EXEC sp_MSforeachtable 'ALT ER   INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = ON)' 
GO

Проверьте такой вариант, имя таблицы автоматом подставляется вместо знака вопроса.
fuser; onetone; MaZaHacKa_13; arkitekt; Sley; maikl007; yaguarrr; +7 Ответить
Остальные ответы
В избранное Подписаться на ответы Сортировка: Древо развёрнутое
Свернуть все
100. bardaknn 11.01.23 08:29 Сейчас в теме
(99) Да я просто мимо проходил.
Особенно смешно про 1Сные приседания))
101. srg123 05.02.23 10:51 Сейчас в теме
(96) Все норм. Все работает. Для тех кто в танке - пробелы лишние уберите в коде FR OM -> FROM и т.д.
(100) Бывает... )
102. alexis9 06.02.23 11:39 Сейчас в теме
Подскажите, пожалуйста.
Поставили платформу 8.3.22.ххх
По некоторым причинам пришлось сразу же откатиться на платформу 8.3.18
И там столкнолись с ошибкой при реиндексации. Судя по всему, реструктуризация БД не учла изменения в БД внесенные платформой 22.
Описаный здесь скрипт помог.
Но у меня вопрос.
Надо ли мне использовать после реиндексации второй скрипт для выключения блокировок?
Ведь сейчас у меня платформа 18, а не 22. А 1с внесла изменения в блокировки только на 22й платформе.
103. kiykomi 08.02.23 16:32 Сейчас в теме
Вот правильная конструкция, которая работает у меня:

До реорганизации индекса:
DECLARE @dbname nvarchar(128)
DECLARE @sql nvarchar(max)
DECLARE db_cursor CURSOR FOR
SEL ECT name FR OM sys.databases
WHERE name NOT IN ('master','tempdb','model','msdb')

OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @dbname

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT @dbname
    SET @sql = 'USE [' + @dbname + '];' +
                'EXEC sp_MSforeachtable ''ALT ER   INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = ON)'';' +
                'EXEC sp_MSforeachtable ''ALT ER   INDEX ALL ON ? SET (ALLOW_ROW_LOCKS = ON)'''
    EXEC (@sql)
    PRINT 'Using database: ' + @dbname
    FETCH NEXT FROM db_cursor INTO @dbname
END

CLOSE db_cursor
DEALLOCATE db_cursor
Показать


И после:
DECLARE @dbname nvarchar(128)
DECLARE @sql nvarchar(max)
DECLARE db_cursor CURSOR FOR
SEL ECT name FROM sys.databases
WH ERE name NOT IN ('master','tempdb','model','msdb')

OPEN db_cursor
FETCH NEXT FR OM db_cursor INTO @dbname

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT @dbname
    SET @sql = 'USE [' + @dbname + '];' +
                'EXEC sp_MSforeachtable ''ALT ER   INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = OFF)'';' +
                'EXEC sp_MSforeachtable ''ALT ER   INDEX ALL ON ? SET (ALLOW_ROW_LOCKS = OFF)'''
    EXEC (@sql)
    PRINT 'Using database: ' + @dbname
    FETCH NEXT FR OM db_cursor INTO @dbname
END

CLOSE db_cursor
DEALLOCATE db_cursor
Показать


Всё отрабатывает отлично.
mfg-super; thunder367; +2 Ответить
106. mfg-super 12.03.23 20:02 Сейчас в теме
(103)
А Вам не кажется, что в скрипте После должно быть так: "ALLOW_PAGE_LOCKS = OFF" и "ALLOW_ROW_LOCKS = ON"?

На ИТС такая информация по этому вопросу:
Важно! Начиная с версии платформы 8.3.22 необходимо выполнять дефрагментацию индексов по следующему алгоритму:
До дефрагментации индекса необходимо включить страничные блокировки. Пример команды: ALT ER INDEX index_name ON table_name SET (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON);
Выполнить дефрагментацию.
Обратно выключить страничные блокировки. Пример команды: ALT ER INDEX index_name ON table_name SET (ALLOW_PAGE_LOCKS = OFF, ALLOW_ROW_LOCKS = ON);
104. kiykomi 08.02.23 16:34 Сейчас в теме
Здесь не нужно указывать базы, просто автоматически берутся все БД, кроме системных и даже обходит ошибку в именах БД со знаком "-" (тире) в имени благодаря квадратным скобкам.
Просто юзайте на здоровье.
105. kiykomi 09.02.23 10:46 Сейчас в теме
Апдейт - чтобы пропускало базы со статусом "Вне сети" добавьте AND state = 0 в конструкцию WHERE name NOT IN ('master','tempdb','model','msdb'), вот так вот:

WHERE name NOT IN ('master','tempdb','model','msdb') AND state = 0
107. TormDV 13.03.23 08:17 Сейчас в теме
Кто-нибудь тестил отключение-включение страничных блокировок сколько времени занимает? Если допустим терабайтная база на сервере крутится или 30-40 баз поменьше... Какую нагрузку включение-отключение создает на сервер?
З.Ы. Сам не проверял, возможно там доли секунды и никаких подводных камней, но вдруг..
108. ESPakhomov 06.04.23 14:33 Сейчас в теме
На сколько вообще корректно использовать:
ALT ER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = ON)
ALT ER INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = OFF)
Если посмотреть индексы до этих манипуляций, то есть индексы у которых изначально ALLOW_PAGE_LOCKS = ON и этими действиями по итогу изменяем их на ALLOW_PAGE_LOCKS = OFF. например:
Прикрепленные файлы:
109. LuMp1ck 08.04.23 06:27 Сейчас в теме
Дай Вам Бог всем здоровья, и долгих лет жизни!

Тоже столкнулся, платформа v8.3.22.1750 + MS SQL 2012

Всё было настроено и всё работало ... но потом ... но потом перестало ))
В результате добавив в план обслуживания шаги на нужных этапах, всё заработало снова!

Единственной, там выше уточняли, что запросе изначально была ошибка ALTER было написано через пробел, поэтому запрос не отрабатывал

USE ERP
EXEC sp_MSforeachtable 'ALT ER   INDEX ALL ON ? SET (ALLOW_PAGE_LOCKS = OFF)'
EXEC sp_MSforeachtable 'ALT ER   INDEX ALL ON ? SET (ALLOW_ROW_LOCKS= ON)'
GO
Прикрепленные файлы:
Anvarich; user1300601; +2 Ответить
110. MDR_Tiger 11.04.23 11:20 Сейчас в теме
Использую такой код для обслуживания индексов в MS SQL 2016:
DECLARE @Base_Name nvarchar(100);
DECLARE @Base_id int;
-- Обрабатываются все пользовательские базы данных в оперативном режиме
DECLARE Bases CURSOR FOR SEL ECT database_id FR OM sys.databases where database_id > 4 and state_desc = 'ONLINE';
-- Обрабатываются только нужные пользовательские базы данных в оперативном режиме
-- DECLARE Bases CURSOR FOR SEL ECT database_id FR OM sys.databases where database_id in (5,6,7,8) and state_desc = 'ONLINE';

OPEN Bases;
FETCH NEXT FR OM Bases INTO @Base_id;
WHILE @@FETCH_STATUS = 0
BEGIN  
-- Отбор таблиц и индексов с помощью системного представления sys.dm_db_index_physical_stats
-- Отбор только тех объектов которые являются индексами (index_id > 0), 
-- фрагментация которых более 10% и количество страниц в индексе более 128
Sel ect @Base_Name = DB_NAME(@Base_id)

PRINT @base_Name;

Exec ('Use ' + @base_Name + '
SET NOCOUNT ON; -- отключаем вывод количества возвращаемых строк, это несколько ускорит обработку
DECLARE @objectid int; -- ID объекта
DECLARE @indexid int; -- ID индекса
DECLARE @partitioncount bigint; -- количество секций если индекс секционирован
DECLARE @schemaname nvarchar(130); -- имя схемы в которой находится таблица
DECLARE @objectname nvarchar(130); -- имя таблицы 
DECLARE @indexname nvarchar(130); -- имя индекса
DECLARE @partitionnum bigint; -- номер секции
DECLARE @frag float; -- процент фрагментации индекса
DECLARE @allow_page_locks int; -- признак включенности блокировки на уровне страниц
DECLARE @command nvarchar(4000); -- инструкция T-SQL для дефрагментации либо ренидексации
	SEL ECT
		IndexStats.object_id AS objectid,
		IndexStats.index_id AS indexid,
		IndexStats.partition_number AS partitionnum,
		IndexStats.avg_fragmentation_in_percent AS frag,
		AllIndexes.allow_page_locks as allow_page_locks
	INTO #work_to_do
	FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, ''LIMITED'') AS IndexStats
	INNER JOIN sys.indexes AS AllIndexes
		ON AllIndexes.index_id = IndexStats.index_id
		AND AllIndexes.object_id = IndexStats.object_id
		AND IndexStats.avg_fragmentation_in_percent > 10.0
		AND IndexStats.index_id > 0
		AND IndexStats.page_count > 128;

	-- Объявление курсора для чтения секций
	DECLARE partitions CURSOR FOR SEL ECT * FR OM #work_to_do;

	-- Открытие курсора
	OPEN partitions;
	-- Цикл по секциям
	WHILE (1=1)
		BEGIN;
			FETCH NEXT
			   FROM partitions
			   INTO @objectid, @indexid, @partitionnum, @frag, @allow_page_locks;

			IF @@FETCH_STATUS < 0 BREAK;
		
	-- Собираем имена объектов по ID		
			SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name)
			FR OM sys.objects AS o
			JOIN sys.schemas as s ON s.schema_id = o.schema_id
			WH ERE o.object_id = @objectid;
			SELECT @indexname = QUOTENAME(name)
			FR OM sys.indexes
			WH ERE  object_id = @objectid AND index_id = @indexid;
			SELECT @partitioncount = count (*)
			FR OM sys.partitions
			WH ERE object_id = @objectid AND index_id = @indexid;

	-- Если фрагментация менее или равна 30% тогда дефрагментация, иначе реиндексация
			IF @frag <= 30.0
				SET @command = N''ALT ER   INDEX '' + @indexname + N'' ON '' + @schemaname + N''.'' + @objectname + N'' REORGANIZE'';
			IF @frag > 30.0
				SET @command = N''ALT ER   INDEX '' + @indexname + N'' ON '' + @schemaname + N''.'' + @objectname + N'' REBUILD'';
			IF @partitioncount > 1
				SET @command = @command + N'' PARTITION='' + CAST(@partitionnum AS nvarchar(10));
			
	-- Если реиндексация, то для ускорения добавляем параметры использования TEMPDB(имеет смысл только если TempDB на отдельном физ. диске) и многопроцессорной обработки 
			IF @frag > 30.0
				SET @command = @command + N'' WITH (SORT_IN_TEMPDB = ON, MAXDOP = 0)'';
			
	-- Принудительное включение блокировки индекса на уровне страницы и её отключение, если блокировка была изначально выключена (для платформы 1С 8.3.22.х)
			IF @allow_page_locks = 0
				BEGIN
					SET @command = N''ALT ER   INDEX '' + @indexname + N'' ON '' + @schemaname + N''.'' + @objectname + N'' SET (ALLOW_PAGE_LOCKS = ON)'' + char(10) + @command;
					SET @command = @command + char(10) + N''ALT ER   INDEX '' + @indexname + N'' ON '' + @schemaname + N''.'' + @objectname + N'' SET (ALLOW_PAGE_LOCKS = OFF)'';
				END

			EXEC (@command);
			PRINT N''Executed: '' + @command;
		END;

	-- Закрытие курсора
	CLOSE partitions;
	DEALLOCATE partitions;

	-- Удаление временной таблицы
	DR OP   TABLE #work_to_do;')
	FETCH NEXT FR OM Bases INTO @Base_id;
END;
CLOSE Bases;
DEALLOCATE Bases;
GO
Показать
fatman78; LineykaSBK; +2 Ответить
112. LineykaSBK 5 25.04.23 22:33 Сейчас в теме
(110)
Спасибо, вроде работает на sql 2019
113. fatman78 16 23.05.23 20:39 Сейчас в теме
(110)
INTO


Прикрепил этот скрипт в виде файла. на MS SQL 2017 с 1С 8.3.22 отлично работает.
Прикрепленные файлы:
SQLQuery_Rebuild_Reindex.sql
114. Vstur 26.05.23 14:29 Сейчас в теме
При откате с 22 платформы на более ранние, достаточно выгрузить в dt и загрузить обратно.
Тогда проблема проблема уйдет
Оставьте свое сообщение
Вакансии
Программист 1С
Екатеринбург
зарплата от 150 000 руб.
Полный день

1С Программист
Москва
зарплата от 180 000 руб. до 220 000 руб.
Полный день

Специалист по технической поддержке пользователей 1С
Москва
зарплата от 70 000 руб.
Полный день

Системный архитектор 1С
Москва
зарплата от 250 000 руб.
Полный день

Системный аналитик (бизнес-аналитика)
Москва
зарплата от 100 000 руб.
Полный день