Адаптивное обновление индексов MS SQL

12.02.25

База данных - Администрирование СУБД

Публикация размещена исключительно в образовательных целях и подходит только для платформы версии 8.3.25.1501.
Использует недокументированные средства доступа к базе данных 1С. Прямое обращение к СУБД нарушает лицензионное соглашение,
может изменить поведение платформы, привести к разрушению базы данных, скомпрометировать данные,
а также привести к отказу в официальной поддержке Фирмы 1С.
Всегда надо обслуживать индексы SQL. В том числе по рекомендации самой 1С. Но обслуживать все и сразу - долго, тяжело серверу и, главное, бессмысленно. Особенно для больших баз. Данный скрипт выбирает, что надо делать, и делает это автоматически. Готового полного аналога не нашел, поэтому сделал этот. Можно примерять для любых конфигураций и платформ 1С. Проверено на 8.3.25.1501.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Адаптивное обновление индексов MS SQL:
.sql 7,49Kb
0
0 Скачать (1 SM) Купить за 1 850 руб.

Параметрический  -каждый параметр можно подстроить под себя

Успешно работает на нескольких серверах

Протестирован на MS SQL 2019

Скрипт адаптивной обработки индекса, если индекс используется активно (параметр) и фрагментирован (параметр) или статистика неактуальна (параметр), то выполняет команды по обслуживанию индекса.

Каждая команда выводит в комментарий - почему она выполнилась.

Также можно как показать, что будет делать, так и выполнить сразу

DECLARE @OnlyShow INT = 0;  --1 = только показать, 0 = еще и выполнить
DECLARE @threshold_modification_pct INT = 1; -- Сколько процентов считать важными изменениями. Таблицы большие и 1% на миллионах –уже 10 000…
DECLARE @minrows INT = 100; -- брать если строк больше в индексе
DECLARE @minused INT = 1000; -- если использовали больше чем 1000 раз
DECLARE @minSteps INT = 10; -- не берем индкесы если они с точки статистики бестолковые
DECLARE @maxRows INT = 100000; -- Или количество строк меньше чем то игнор предыдущее условие
DECLARE @FragsLevel INT = 5; -- дефраг только если больше
DECLARE @FragsLevelRebuild INT = 30; -- rebuild если фрагментация больше
DECLARE @EnterpriseEdition INT = 0; --case when SERVERPROPERTY ('edition')='Enterprise Edition (64-bit)' then 1 else 0 end

---- служебные переменные

DECLARE @command NVARCHAR(500);
DECLARE @TableName SYSNAME;
DECLARE @IndexName SYSNAME;
DECLARE @modification_counter NVARCHAR(200);
DECLARE @Table_rows NVARCHAR(200);
DECLARE @Table_used NVARCHAR(200);
DECLARE @Steps NVARCHAR(200);
DECLARE @avg_fragmentation_in_percent NUMERIC;
DECLARE @levelForDefrag NUMERIC;
DECLARE @Frag NVARCHAR(200);
DECLARE @Variant NVARCHAR(20);

 

DECLARE indexes CURSOR FOR
  SELECT 
         obj.NAME                                    [table],
         stat.NAME                                   [index],
         modification_counter                        [modification_counter],
         sp.rows                                     [Table_rows],
         user_seeks + user_scans + user_lookups      AS Table_used,
         sp.steps                                    Steps,
         ips.avg_fragmentation_in_percent            AS  avg_fragmentation_in_percent  ,
         ips.avg_fragmentation_in_percent            AS Frag,
         sp.rows * @threshold_modification_pct / 100 AS levelForDefrag,
         CASE
           WHEN modification_counter >
                sp.rows * @threshold_modification_pct / 100
                    THEN
                           N'UPDATE STATISTICS'
           WHEN ips.avg_fragmentation_in_percent > @FragsLevelRebuild THEN
                           'REBUILD'
           ELSE 'REORGANIZE'
         END                                         AS Variant
  FROM   sys.objects AS obj
         INNER JOIN sys.stats AS stat
                 ON stat.object_id = obj.object_id
         CROSS apply sys.Dm_db_stats_properties(stat.object_id, stat.stats_id)
                     AS
                     sp
         LEFT JOIN (SELECT *
                    FROM   sys.Dm_db_index_physical_stats(Db_id(), NULL, NULL,
                           NULL, NULL
                           )) AS ips
                ON stat.object_id = ips.object_id
                   AND stat.stats_id = ips.index_id
         INNER JOIN sys.dm_db_index_usage_stats AS s
                 ON stat.object_id = s.object_id
                    AND stat.stats_id = s.index_id
  WHERE  s.database_id = Db_id()
         AND obj.type = 'U'
         AND stat.NAME NOT LIKE ( '_WA%' )
         AND ips.alloc_unit_type_desc = 'IN_ROW_DATA'
         AND @minrows < sp.rows
         AND ( user_seeks + user_scans + user_lookups ) >= @minused
         AND ( ips.avg_fragmentation_in_percent > @FragsLevel
                OR ( modification_counter >
                     sp.rows * @threshold_modification_pct / 100 )
             )
         AND ( sp.steps > @minSteps
                OR @maxRows > sp.rows )
  --ORDER  BY stat.NAME
  ; ---(user_seeks + user_scans + user_lookups) desc;
 
OPEN indexes;

WHILE ( 1 = 1 )
  BEGIN
      FETCH next FROM indexes INTO @TableName, @IndexName, @modification_counter    ,
      @Table_rows, @Table_used, @Steps, @avg_fragmentation_in_percent, @Frag,
      @levelForDefrag,@Variant;
 
      IF @@FETCH_STATUS < 0
        BREAK;
 
      IF @levelForDefrag < @modification_counter
        SET @command = N'UPDATE STATISTICS dbo.' + @TableName + ' '
                       + @IndexName
                       + N' WITH FULLSCAN, MAXDOP=8; --  Steps '
                       + @Steps + ', used ' + @Table_used + ', changed '
                       + @modification_counter + ' rows of '
                       + @Table_rows;
      ELSE
        SET @command =
             CASE
                    WHEN @variant='REBUILD'
               THEN
                                  ''
                          ELSE
                                  N'ALTER INDEX ' + @IndexName + ' on dbo.' + @TableName+ ' SET (ALLOW_PAGE_LOCKS = ON, ALLOW_ROW_LOCKS = ON);'
                           END
                    + N'ALTER INDEX ' + @IndexName + ' on dbo.'  + @TableName
                    + CASE
                           WHEN @variant='REBUILD'
                                  THEN
                                  ' REBUILD WITH (SORT_IN_TEMPDB = ON, maxdop=8' + case When @EnterpriseEdition=1 then ', online=on' else '' end +')'
                           ELSE
                                  ' REORGANIZE '
                      END
                    + CASE
                           WHEN @variant='REBUILD'
                                  THEN
                                        ''
                           ELSE
                                  N'; ALTER INDEX ' + @IndexName + ' on dbo.' + @TableName+ ' SET (ALLOW_PAGE_LOCKS = OFF, ALLOW_ROW_LOCKS = ON)'
                           END
                    + '; --- frag = ' + @Frag + '%'   + ', rows = ' + @Table_rows;
 
      PRINT N'Executed: ' + @command;
 
      IF @OnlyShow = 1
        CONTINUE;
 
      EXEC (@command);
  END;
 

CLOSE indexes;

DEALLOCATE indexes;
 

 

Обслуживание индексов MS SQL

См. также

HighLoad оптимизация Администрирование СУБД Программист Платформа 1С v8.3 Бесплатно (free)

В рамках мастер-класса мы запустим нагрузочный тест на 3К пользователей и посмотрим, как будет вести себя PostgreSQL при такой нагрузке.

11.12.2024    1675    Tantor    1    

6

Администрирование СУБД Программист Платформа 1С v8.3 1C:Бухгалтерия Россия Бесплатно (free)

Много вариантов определения номера собственного процесса самого 1С8. В ходе поиска, опираясь на общедоступную информацию, дополнил алгоритм, но с учетом определения ИД запущенного приложения.

09.12.2024    783    artly2000    6    

4

Администрирование СУБД Системный администратор Программист

В крупных компаниях, где много типовых и сильно доработанных баз с режимом работы 24/7, переход с MS SQL на PostgreSQL затягивается. Получается гетерогенная структура – когда прод уже на PostgreSQL, а разработка и тестирование – пока на MS SQL. О том, какие варианты помогут постепенно перевести прод с несколькими базами MS SQL на PostgreSQL, не сломав среду тестирования и разработки, пойдет речь в статье.

21.11.2024    4043    a.doroshkevich    8    

16

HighLoad оптимизация Администрирование СУБД Системный администратор Программист Платформа 1С v8.3 Россия Бесплатно (free)

Мы исследуем проблему долгого выполнения запросов PostgreSQL при использовании конструкции VALUES: когда она возникает, как на нее можно повлиять, а главное, почему ее продуманная отработка важна для более быстрого функционирования решений на базе 1С

12.11.2024    1556    Tantor    20    

18

HighLoad оптимизация Администрирование СУБД Механизмы платформы 1С Программист Платформа 1С v8.3 ИТ-компания Россия Бесплатно (free)

В данной статье мы рассмотрим, как работает механизм временных таблиц на postgres на платформе 8.3.23 и что изменилось в нем при добавлении новых возможностей в платформе 8.3.25. А также на примере покажу, как понимание работы платформы позволяет оптимизировать СУБД для работы с 1С.

29.10.2024    5064    Tantor    38    

37

Администрирование СУБД Системный администратор Программист Бесплатно (free)

CDC - очень мощный механизм, который можно использовать во многих сценариях, возможность развернуть его в Docker показывает простоту и лёгкость данной технологии.

08.10.2024    1681    AlexSvoykin    2    

7

Администрирование СУБД Системный администратор Программист Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Анализ и решение ошибок СУБД. Во время реиндексации базы Ошибка СУБД: Microsoft SQL Server Native Client 11.0: Не удалось найти объект "ИмяБазы.dbo._RefSInf21806", так как он не существует, или отсутствуют разрешения. Во время проверки целостности Ошибка СУБД: Microsoft SQL Server Native Client 11.0: Недопустимое имя объекта "dbo._RefSInf21806".

19.09.2024    6682    Xershi    10    

21
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. paulwist 12.02.25 10:50 Сейчас в теме
DECLARE @threshold_modification_pct INT = 1; -- Сколько процентов считать важными изменениями. Таблицы большие и 1% на миллионах –уже 10 000…


Если уж речь про большие таблицы, то тип INT явно не подходит для дробных процентов :)
5. GreyCardinal 3 13.02.25 10:34 Сейчас в теме
(1Согласен но в реальности на нашей базе (есть и по 200кк строк) оптимально что инт
не будет колебаний расчитывать до долей процентов параметр )
2. PerlAmutor 157 13.02.25 06:31 Сейчас в теме
Есть такой живой проект от Ola Hallengren с 2008 года. Умеет многое. Виктор Богачев упоминал, что он не панацея т.к. для достаточно больших баз требуются определенные исключения некоторых таблиц из обработки, плюс там вроде как нет реальной параллельности обслуживания индексов.

https://github.com/olahallengren/sql-server-maintenance-solution
3. paulwist 13.02.25 09:58 Сейчас в теме
(2)
плюс там вроде как нет реальной параллельности обслуживания индексов.


Это невозможно by design для одной таблицы, поскольку при параллельном процессе двух разных сессий на табличку накладываются несовместимые блокировки.
8. PerlAmutor 157 13.02.25 19:05 Сейчас в теме
(3) Да хотя бы для разных - тоже нету.
4. GreyCardinal 3 13.02.25 10:33 Сейчас в теме
(2)Смотрел
почему сделал свой
1-понятнее что делает - без излишков
2 не нужны доп функции на сервере создавать
3-сам смотрит какие обрабатывать - минимум настроек

у нас работает на ДО и ЗУП
разные базы - для админов настройка одна
6. redfred 13.02.25 15:12 Сейчас в теме
Автоматически создаваемая статистика ( '_WA%' ) тут не обновляется, получается?
7. GreyCardinal 3 13.02.25 17:10 Сейчас в теме
(6) Никто не мешает закомментить
AND stat.NAME NOT LIKE ( '_WA%' )
но как правило раз стоит автосоздание - наверняка и автообновление
но на автообновление уже нарвались - сносит что было и обновляет по части
поэтому выбрали управляемое действо
9. redfred 14.02.25 07:00 Сейчас в теме
(7)
Никто не мешает закомментить
AND stat.NAME NOT LIKE ( '_WA%' )


Боюсь, что не поможет. У вас список на основе sys.objects строится, там в принципе статистик нет.

(7)
но как правило раз стоит автосоздание - наверняка и автообновление


Наверняка. Но ведь и для остальных, не автосоздаваемых, оно стоит, но ведь их скриптом-то обновляете.

Ну ладно, бог с ним. Скажите, из каких соображений обрабатываются только топ 10 индексов? При том, что сортировка закомментирована.
10. GreyCardinal 3 14.02.25 10:12 Сейчас в теме
(9) Очепятка от теста- убрал

автообновление убрали у всех

так как данные меняются - автообновление берет часть для статистики - в итоге ломается
11. redfred 14.02.25 10:58 Сейчас в теме
(10) Понятно. Т.е автообновление отключено, но, при этом, часть статистик выпадает из обработки (не из-за sys.objects, как мне сперва показалось, на джойне с dm_db_index_usage_stats). Ну, ок, тут не берусь судить насколько это принципиально именно для 1С
12. GreyCardinal 3 14.02.25 11:30 Сейчас в теме
(11) Скажем так - анализ текущих запросов не выявил других проблем
Если найдутся - будем решать
13. GreyCardinal 3 14.02.25 12:07 Сейчас в теме
(11)
берутся как раз не все - а которые часто используются-минимум кастомизации
в 1с запрещено лицензией создавать свои
- поэтому для 1с этот скрип "кошерный"
14. redfred 14.02.25 12:34 Сейчас в теме
По текущей логике скрипта автосоздаваемые статистики не берутся ни при каком условии. Они у вас безальтернативно отфильтровываются, т.к. они "безиндексные" и про них нет записей в соотв. dmv.
Но если проблем нет - то проблем нет
Оставьте свое сообщение