MSSQL. Переиндексация в несколько потоков

06.12.24

База данных - Инструменты администратора БД

Набор скриптов MSSQL и описание их работы.

Скачать файл

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

Наименование По подписке [?] Купить один файл
MSSQL Переиндексация в несколько потоков:
.zip 3,71Kb
4
4 Скачать (1 SM) Купить за 1 850 руб.

Переиндексация в несколько потоков.

Не раз слышал мнения 1сников, что переиндексации вообще не нужна. Так как мы живем сейчас в век ssd и nvme. И неважно, какая у вас фрагментация индекса, нужно просто делать обновление статистики и все. И как подтверждение кидают абзац от Microsoft

 

 

Но почему – то не читают начало этой статьи, в которой сказано, как влияет фрагментация и плотность страниц на общую производительность. И расход ресурсов

 

 

И то, что даже на ssd и NMVE последовательная скорость чтения запись всегда выше, чем случайная

 

 

И про плотность, (если у вас, конечно, на сервере на 2ТБ памяти на базу 2ТБ)

 

 

Подытожим. Обновление статистики и правда даст вам сиюминутный эффект. Но со временем фрагментация сделает свое, и вам не хватает уже мощностей железа, чтобы перекрыть тормоза.

Так что мое мнение - переиндексация нужна! Но не нужно каждый день перестраивать все индексы) Благо всевозможных скриптов хватает в сети.

Идея появилась из-за проблемы, что база в 20 ТБ не могла за выделенное техокно пройти «полную» переиндексацию. И через неделю-две начинались дикие тормоза, и обновление статистики не давало явного ускорения. Пробовал чужие скрипты с паузой и прочие. Но во всех скриптах перестройка индексов идет в один поток (я говорю не про maxdop). Что пока один индекс не перестроится, другие не начнут.  Так что вот представляю мой костыль)

Скрипт представляю в немного урезанном виде и на 2 потока.

Шаги в скрипте.

  1. Собрать статистику по всем индексам в базе их фрагментации и размеру. Занести данные в служебную базу.
  2. Выполнить задание перестройки по первой половине данных
  3. Выполнить задание перестройки по второй половине данных
  4. Обновить статистику, по всей базе.

Зачем, вы спросите, обновлять статистику по всей базе, если переиндексация обновляет статистику? А я отвечу. Мы перестраиваем не все таблицы, часть с малой фрагментацией мы пропускаем. А таблицы с только что перестроенными индексами (при условии, что не было еще ни одной вставки) будут пропущены, с сообщение, что нечего там обновлять. Это проще чем делать еще один шаг с условием. Что если переиндексация по таблице не проходила, то обнови статистику.

Можно все сделать разными jobs с привязкой старта разным логом и прочим. Но так как это lite версия скрипта, пример будет создан на maintenance Plan.

Так как я встречал моветон имена БД через – а не _ , что заставляет городить конструкции с выделением имени БД в несколько кавычек (так как – в скриптах это может быть как действием, так и символом).

Поэтому в скрипте есть 2 разные «переменные» DATA-BASE(Имя базы) и DATA_BASE(Служебная переменная). Во всех файлах необходимо заменить  DATA-BASE имя вашей БД (к примеру SP-UPP), DATA_BASE заменить (SPUPP или SP_UPP)

Скрипт на первом шаге, создает служебную базу profiler (если ее нет). Собираем статистику по индексам и заполняем базу profiler. Сбор статистики - достаточно долгий процесс, который не сильно влияет на скорость. То есть 1 шаг лучше запускать заранее. К примеру, техокно у вас с 21:00 часа, первый шаг у вас выполняется за 40 мин. и не мешает пользователям, то статистику можно начать собирать в 20:20.

 

  1. SET QUOTED_IDENTIFIER ON;
    
    if DB_ID('profiler') IS NULL
    BEGIN
     PRINT 'Creating Profiler database'
     CREATE DATABASE Profiler
    END
    
    declare @astor_name VARCHAR(255)
    declare @astor_id INT
    SELECT TOP 1 @astor_name = QUOTENAME(name), @astor_id=database_id FROM sys.databases where name like 'DATA-BASE'
    DECLARE @rebuildOptions nvarchar(MAX) = N' WITH (maxdop = 10, ONLINE = ON, SORT_IN_TEMPDB = ON)'
    DECLARE @partitionnum bigint;
    DECLARE @partitions bigint;
    DECLARE @objectid int;
    DECLARE @indexid int;
    DECLARE @partitioncount bigint;
    
    PRINT 'Woring with ' + @astor_name 
    
    DECLARE @indexTable VARCHAR(255) 
    SET @indexTable= @astor_name + '.sys.indexes'
    
    if OBJECT_ID('temporary_indexes_DATA_BASE') IS NOT NULL 
     DROP VIEW temporary_indexes_DATA_BASE;
    
    EXEC('CREATE VIEW temporary_indexes_DATA_BASE AS 
      SELECT 
        idx.object_id as object_id, 
        idx.index_id as index_id,
        sch.name as schema_name,
        obj.name as table_name,
        idx.name as index_name,
        idx.type_desc as type_desc 
       FROM ' + @astor_name + '.sys.indexes as idx
       JOIN '  + @astor_name + '.sys.objects as obj ON obj.object_id = idx.object_id
       JOIN '  + @astor_name + '.sys.schemas as sch ON sch.schema_id = obj.schema_id')
    
    DECLARE @FramentationReportTable VARCHAR(255) 
    SET @FramentationReportTable = 'Fragmentation_DATA_BASE_'+REPLACE(convert(varchar, getdate(), 102), '.', '_')
    
    IF OBJECT_ID('tempdb..##fragmentation_DATA_BASE') IS NOT NULL
     DROP TABLE ##fragmentation_DATA_BASE
    
    DECLARE @reportNum INT 
    SET @reportNum = 1
    
    WHILE OBJECT_ID('[Profiler].dbo.' + @FramentationReportTable+'_' + CAST(@reportNum AS nvarchar(255))) IS NOT NULL  
     SELECT @reportNum = @reportNum + 1;
    
    SELECT @FramentationReportTable = @FramentationReportTable + '_' + CAST(@reportNum AS nvarchar(255))
    
    DROP SEQUENCE IF EXISTS Sequence;
    CREATE SEQUENCE Sequence
        START WITH 1  
        INCREMENT BY 1  
        MINVALUE 1  
        MAXVALUE 2  
        CYCLE  
    
    RAISERROR( N'Analyzing indexes',0,1) WITH NOWAIT
    SELECT
     DB_NAME(stats.database_id) as db_name,
     idx.schema_name as schema_name,
     idx.table_name AS table_name,
        idx.index_name AS index_name,
     idx.type_desc as index_type,
        stats.partition_number AS partition_num,
        stats.avg_fragmentation_in_percent AS fragmentation,
     stats.avg_page_space_used_in_percent as page_fullness,
     stats.avg_record_size_in_bytes as record_size,
     stats.record_count as rows_count,
     stats.page_count as page_count
     --- ,next value for Sequence over (order by [record_count] desc) as num
    INTO ##fragmentation_DATA_BASE
    FROM sys.dm_db_index_physical_stats (@astor_id, NULL, NULL , NULL, 'SAMPLED') as stats
    JOIN temporary_indexes_DATA_BASE idx ON idx.object_id = stats.object_id and idx.index_id = stats.index_id
    DROP VIEW temporary_indexes_DATA_BASE
    
    EXEC ('SELECT [db_name]
          ,[schema_name]
          ,[table_name]
          ,[index_name]
          ,[index_type]
          ,[partition_num]
          ,[fragmentation]
          ,[page_fullness]
          ,[record_size]
          ,[rows_count]
          ,[page_count]
       ,next value for Sequence over (order by ROUND ([fragmentation],0 ) desc, [rows_count] desc) as num INTO profiler.dbo.'+ @FramentationReportTable +' FROM ##fragmentation_DATA_BASE')
    

     

2 и 3 шаги почти идентичные кроме условия условий выбора и названия курсора.

 

  1. DECLARE @FramentationReportTable_1 VARCHAR(255) 
    SET @FramentationReportTable_1 = (SELECT top 1 table_name FROM Profiler.INFORMATION_SCHEMA.TABLES  WHERE table_Name LIKE 'Fragmentation_DATA_BASE_'+REPLACE(convert(varchar, getdate(), 102), '.', '_') + '%')
    print @FramentationReportTable_1
    
    exec ('
    DECLARE bad_indexes_1 CURSOR FOR 
     
     select
     frag.db_name,
     frag.schema_name,
     frag.table_name,
     frag.index_name,
     frag.partition_num,
     case
      when frag.record_size*16 <= 403 then 95
      when frag.record_size*16 <= 806 then 90
      when frag.record_size*16 <= 1209 then 85
      else 80
     end as suggested_fillfactor
     
     
     from Profiler.dbo.'+ @FramentationReportTable_1 +' frag
     where frag.page_count > 24 and frag.fragmentation >= 5  and frag.num = 1  and frag.index_type <>''HEAP''
     order by ROUND ([fragmentation],0 ) desc, [rows_count] desc')
    
    
    -- Open the cursor.
    OPEN bad_indexes_1
    
    DECLARE @db_name nvarchar(130);
    DECLARE @schema_name nvarchar(130);
    DECLARE @table_name nvarchar(130);
    DECLARE @index_name nvarchar(130);
    DECLARE @fragmentation bigint;
    DECLARE @suggested_fillfactor int;
    DECLARE @partition_num bigint;
    DECLARE @partitionOption nvarchar(130);
    DECLARE @fillfactorOption nvarchar(130);
    DECLARE @object_name nvarchar(1000);
    DECLARE @command nvarchar(1000);
    DECLARE @time nvarchar(130)
    
    WHILE (1=1) 
     BEGIN
     FETCH NEXT
               FROM bad_indexes_1
               INTO @db_name, @schema_name, @table_name, @index_name, @partition_num, @suggested_fillfactor;
    
     IF @@FETCH_STATUS < 0 BREAK
     
     
    
       IF @partition_num > 1
       begin
        SET @partitionOption = N' PARTITION=' + CAST(@partition_num AS nvarchar(10));
        set @fillfactorOption = N''
       end
      else 
       begin
        SET @partitionOption = N''
        set @fillfactorOption = N' FILLFACTOR=' + CAST(@suggested_fillfactor as nvarchar(10)) + N', '
       end
    
     SET @object_name = QUOTENAME(@db_name) + N'.' + QUOTENAME(@schema_name) + N'.' + QUOTENAME(@table_name)
     BEGIN TRY
    
        SET @command = N'ALTER INDEX ' + QUOTENAME(@index_name) + N' ON ' + @object_name + ' REBUILD ' + @partitionOption +' WITH(' + @fillfactorOption +  N'maxdop = 0, ONLINE = ON, SORT_IN_TEMPDB = ON, MAX_DURATION = 10 minutes, ABORT_AFTER_WAIT = BLOCKERS)'
      set @time = CURRENT_TIMESTAMP;
      print @time
      RAISERROR(@command, 0, 1)
      EXEC(@command)
      set @time = CURRENT_TIMESTAMP;
      RAISERROR(N'DONE', 0, 1) 
     END TRY
     BEGIN CATCH
         SET @command = N'ALTER INDEX ' + QUOTENAME(@index_name) + N' ON ' + @object_name + ' REBUILD ' + @partitionOption +' WITH(' + @fillfactorOption +  N'maxdop = 0, SORT_IN_TEMPDB = ON)'
     set @time = CURRENT_TIMESTAMP;
      print @time
      RAISERROR(@command, 0, 1)
      EXEC(@command)
      set @time = CURRENT_TIMESTAMP;
      RAISERROR(N'DONE', 0, 1) 
      print @time
     END CATCH
    END
    
    close bad_indexes_1
    deallocate bad_indexes_1

     

  2. DECLARE @FramentationReportTable_2 VARCHAR(255) 
    SET @FramentationReportTable_2 = (SELECT top 1 table_name FROM Profiler.INFORMATION_SCHEMA.TABLES  WHERE table_Name LIKE 'Fragmentation_DATA_BASE_'+REPLACE(convert(varchar, getdate(), 102), '.', '_') + '%')
    print @FramentationReportTable_2
    
    exec ('
    DECLARE bad_indexes_2 CURSOR FOR 
     
     select
     frag.db_name,
     frag.schema_name,
     frag.table_name,
     frag.index_name,
     frag.partition_num,
     case
      when frag.record_size*16 <= 403 then 95
      when frag.record_size*16 <= 806 then 90
      when frag.record_size*16 <= 1209 then 85
      else 80
     end as suggested_fillfactor
     
     
     from Profiler.dbo.'+ @FramentationReportTable_2 +' frag
     where frag.page_count > 24 and frag.fragmentation >= 5  and frag.num = 2  and frag.index_type <>''HEAP''
     order by ROUND ([fragmentation],0 ) desc, [rows_count] desc')
    
    
    -- Open the cursor.
    OPEN bad_indexes_2
    
    DECLARE @db_name nvarchar(130);
    DECLARE @schema_name nvarchar(130);
    DECLARE @table_name nvarchar(130);
    DECLARE @index_name nvarchar(130);
    DECLARE @fragmentation bigint;
    DECLARE @suggested_fillfactor int;
    DECLARE @partition_num bigint;
    DECLARE @partitionOption nvarchar(130);
    DECLARE @fillfactorOption nvarchar(130);
    DECLARE @object_name nvarchar(1000);
    DECLARE @command nvarchar(1000);
    DECLARE @time nvarchar(130)
    
    WHILE (1=1) 
     BEGIN
     FETCH NEXT
               FROM bad_indexes_2
               INTO @db_name, @schema_name, @table_name, @index_name, @partition_num, @suggested_fillfactor;
    
     IF @@FETCH_STATUS < 0 BREAK
     
     
    
       IF @partition_num > 1
       begin
        SET @partitionOption = N' PARTITION=' + CAST(@partition_num AS nvarchar(10));
        set @fillfactorOption = N''
       end
      else 
       begin
        SET @partitionOption = N''
        set @fillfactorOption = N' FILLFACTOR=' + CAST(@suggested_fillfactor as nvarchar(10)) + N', '
       end
    
     SET @object_name = QUOTENAME(@db_name) + N'.' + QUOTENAME(@schema_name) + N'.' + QUOTENAME(@table_name)
     BEGIN TRY
     
        SET @command = N'ALTER INDEX ' + QUOTENAME(@index_name) + N' ON ' + @object_name + ' REBUILD ' + @partitionOption +' WITH(' + @fillfactorOption +  N'maxdop = 0, ONLINE = ON, SORT_IN_TEMPDB = ON, MAX_DURATION = 10 minutes, ABORT_AFTER_WAIT = BLOCKERS)'
      set @time = CURRENT_TIMESTAMP;
      print @time
      RAISERROR(@command, 0, 1)
      EXEC(@command)
      set @time = CURRENT_TIMESTAMP;
      RAISERROR(N'DONE', 0, 1) 
     END TRY
     BEGIN CATCH
       SET @command = N'ALTER INDEX ' + QUOTENAME(@index_name) + N' ON ' + @object_name + ' REBUILD ' + @partitionOption +' WITH(' + @fillfactorOption +  N'maxdop = 0, SORT_IN_TEMPDB = ON)'
     set @time = CURRENT_TIMESTAMP;
      print @time
      RAISERROR(@command, 0, 1)
      EXEC(@command)
      set @time = CURRENT_TIMESTAMP;
      RAISERROR(N'DONE', 0, 1) 
      print @time
     END CATCH
    END
    
    close bad_indexes_2
    deallocate bad_indexes_2

     

В скриптах 2 и 3 есть пара моментов, которые я хочу прояснить.

- есть проверка на партиции, и в зависимости от этого будет меняться запрос.

- есть изменение fillfactor в зависимости от record_size

- идет 2 условия. Пробует перестроить индекс online и с ожиданием, если не удается, то перестраивает индекс просто.

- RAISERROR со временем было сделано для того, чтобы узнать время начала переиндексации по таблице и конца (Здесь осталось как отладочная команда). Эту инфу можно передать в другую базу для истории или диагностики.

4. Обновление статистики.

 

USE [DATA-BASE] 
        GO  
        EXEC sp_updatestats;

 

Если вдруг вы хотите добавить потоков, то необходимо будет в скрипте 1. Изменить параметр в SEQUENCE

Установить MAXVALUE на значение желаемых потоков и создать шаг наподобие 2 или 3.

Но тут нужно хорошо думать. Так как переиндексация достаточно сильно нагружаемый процесс. И можно поставить сервер колом, если делать несколько alter index сразу.

После пары запусков с разными настройками удалось добиться 30-40% выигрыша по времени. И задание успевает выполниться за техокно.

Переиндексация MSSQL регламентные задания Microsoft SQL Server ALTER INDEX REBUILD

См. также

Инструментарий разработчика Чистка данных Свертка базы Инструменты администратора БД Системный администратор Программист Руководитель проекта Платформа 1С v8.3 Россия Платные (руб)

Инструмент представляет собой обработку для проведения свёртки или обрезки баз данных. Работает на ЛЮБЫХ конфигурациях (УТ, БП, ERP и т.д.). Поддерживаются серверные и файловые базы, управляемые и обычные формы. Может выполнять свертку сразу нескольких баз данных и выполнять их автоматически без непосредственного участия пользователя. Решение в Реестре отечественного ПО

8400 руб.

20.08.2024    12570    99    42    

101

Инструменты администратора БД Роли и права Системный администратор Программист Пользователь 8.3.14 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:Документооборот 1С:Зарплата и кадры государственного учреждения 3 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Зарплата и Управление Персоналом 3.x 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Платные (руб)

Роли… Вы тратите много времени и сил на подбор ролей среди около 2400 в ERP или 1500 в Рознице 2, пытаясь понять какими правами они обладают? Вы все время смотрите права в конфигураторе или отчетах чтоб создать нормальные профили доступа? Вы хотите наглядно видеть какие права дает профиль и редактировать все в простом виде? А может хотите просто указать подсистему и дать права на просмотр и добавление на объекты и не лезть в дебри прав и чтоб обработка сама подобрала нужные роли? Все это теперь стало возможно! Обновление от 18.09.2024, версия 1.2

18000 руб.

06.12.2023    9991    48    5    

78

SALE! %

Инструментарий разработчика Инструменты администратора БД Системный администратор Программист Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Россия Платные (руб)

Универсальный инструмент программиста для администрирования конфигураций. Сборник наиболее часто используемых обработок под единым интерфейсом.

4800 3840 руб.

14.01.2013    190534    1150    0    

918

Инструменты администратора БД Инструментарий разработчика Роли и права Программист Платформа 1С v8.3 Конфигурации 1cv8 Россия Платные (руб)

Расширение позволяет без изменения кода конфигурации выполнять проверки при вводе данных, скрывать от пользователя недоступные ему данные, выполнять код в обработчиках. Не изменяет данные конфигурации, легко устанавливается практически на любую конфигурацию на управляемых формах.

15000 руб.

10.11.2023    11387    40    27    

66

Закрытие периода Инструменты администратора БД Корректировка данных Бухгалтер Пользователь Бухгалтерский учет 1С:Бухгалтерия 3.0 Россия Бухгалтерский учет Платные (руб)

Расширение «Оперативное проведение» в 4 раза уменьшает время проведения документов и закрытия месяца. Является комплексным решением проблем 62 и 60 счетов. Оптимизирует проведение при включенной функциональной опции «Раздельный учет НДС». Используется в более 10 организациях уже 2 года. Совместимо с конфигурацией Бухгалтерия 3.0 (+КОРП).

14400 руб.

29.04.2020    33578    109    152    

74

Инструменты администратора БД Системный администратор Программист Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Брандмауэр для сервера 1С включает в себя управление возможностью начала и возобновления сеансов пользователей по различным условиям, ограничение общего числа возможных сеансов для работы с информационной базой, резервирование возможности работы с информационной базой определенных польззователей, запрет запуска нескольких сеансов для пользователя, журнализация событий начала (возобновления) и завершения (гибернации) сеансов, ведение списка активных сеансов для информационных баз кластера серверов

3600 руб.

06.02.2017    32485    145    18    

51

Архивирование (backup) Инструменты администратора БД Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:Управление торговлей 11 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Платные (руб)

Данная разработка позволит решить вопрос с резервным копированием Ваших баз в автоматическом режиме, расположенных на сервере 1С. Система умеет ставить блокировки на вход, блокировать фоновые задания, принудительно отключать сеансы пользователей. И все это система делает в автоматически при создании бэкапа (или через команду). Выгрузка происходит в родной формат 1С - .dt. Так же система умеет архивировать данные выгрузки с установкой пароля. Умеет менять расширение файла zip или dt на любое указанное вами, что позволит сохранить выгрузки от шифровальщика. Может удалять старые копии выгрузок, оставляя указанное количество резервных копий, начиная с самой поздней. Только для WINDOWS!

6000 руб.

06.11.2012    73522    629    45    

88

Инструменты администратора БД Пользователь Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Платные (руб)

Многие сталкиваются с проблемой когда изображения, находящиеся в базе разные по объему и размерам. Менеджеры могут добавить файлы в очень высоком разрешении, объемом свыше 20 Мегабайт. База данных становится слишком большой, выгрузка на сайт идёт медленно и требуется много место на хостинге. Как сжать картинки и уменьшить размер базы 1С? Это можно сделать с помощью данной обработки. Существует возможность выбрать различные варианты для того чтобы уменьшить картинки: в разы, в процентах от первоначального объема, а также сделать картинки одинаковой ширины. В результате размер базы 1С значительно сократится (в зависимости от количества и размера картинок), а изображения станут небольшого объема, равными по ширине, почти без потери качества. Работает на управляемых формах для УТ 11, КА, ERP.

3000 руб.

21.07.2022    10091    9    4    

17
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. darminov 106 07.12.24 06:59 Сейчас в теме
Доброе утро. Мы создаем служебную базу profiler (если ее нет) создается просто пустая база?
2. roma_mef 14 07.12.24 07:30 Сейчас в теме
(1) Да, немного не корректно написал видимо. Исправил, что скрипт создает базу, если ее нет.
База создается пустая, с дефолтным расположением. За это отвечает вот этот кусок кода.

if DB_ID('profiler') IS NULL
BEGIN
 PRINT 'Creating Profiler database'
 CRE ATE     DATABASE Profiler
END
3. darminov 106 07.12.24 07:41 Сейчас в теме
(2) спасибо. хочу сегодня попробовать использовать ваш скрипт. у нас за 2 ТБ и не успевает проиндексироваться.
Подскажи вы не поднимали совместимость SQL? у нас сейчас на базе стоит совместимость SQL Server 2008 (100)
5. roma_mef 14 07.12.24 07:52 Сейчас в теме
(3) У нас совместимость 2016(130) стоит. Так же советую посмотреть на условия переиндексации. во 2 и 3 скрипте maxdop = 0, ON LINE = ON, SORT_IN_TEMPDB = ON, MAX_DURATION = 10 minutes, ABORT_AFTER_WAIT = BLOCKERS)

Я ставил без ограничения по потокам (на базе у нас стоит ограничение 2). Пробовать ONLINE - у вас может не работать из за выпуска sql. И так же в скрипте есть ожидание блокировок и что делать после 10 мин. MAX_DURATION = 10 minutes, ABORT_AFTER_WAIT = BLOCKERS.
Так что попробуйте сначала на тестовой базе.
7. darminov 106 07.12.24 07:56 Сейчас в теме
(5) понял. спасибо. сейчас буду пробовать на копии тогда
4. darminov 106 07.12.24 07:43 Сейчас в теме
Так же подскажите в статье прописано Поэтому в скрипте есть 2 разные «переменные» DATA-BASE(Имя базы) и DATA_BASE(Служебная переменная). Во всех файлах необходимо заменить DATA-BASE имя вашей БД (к примеру SP-UPP), DATA_BASE заменить (SPUPP или SP_UPP)
Как понимаю DATA-BASE(Имя базы) это рабочая база, а это тогда что DATA_BASE? на что изменять?
6. roma_mef 14 07.12.24 07:54 Сейчас в теме
(4) Если у вас база в название не содержит символов - и прочих то обе переменные можно заменить на имя БД. DATA_BASE используется как переменная и как часть названия таблицы в базе profiler
8. roma_mef 14 07.12.24 08:35 Сейчас в теме
(4) Вот рабочий пример
У меня есть 2 базы одна через - SP-UPP и другая просто UPP
в первом случае, я меняю DATA-BASE на имя базы SP-UPP, а DATA_BASE пишу имя базы без тире -, SPUPP тогда в скрипте не нужно выделять символ - в ковычки.
А во втором случае оба этих значения пишу как UPP
Прикрепленные файлы:
9. darminov 106 07.12.24 08:37 Сейчас в теме
(8) спасибо. а вообще стоит поднять совместимость? сам SQL стоит 2017. и можно поднять совместимость до SQL Server 2017 (140). Если поднять ускорится работа в самой базе?
10. roma_mef 14 07.12.24 09:12 Сейчас в теме
(9) Я бы не советовал поднимать совместимость на много версий сразу. Один раз попал на проблему со старым кодом когда сильно поднял совместимость. Но так да желательно поднимать совместимость так как много "улучшений" сервера начинает работать. Точно бы советовал проверить эту настройку на базе sql target recovery time, это "время выгрузки dirty pages". на старых база он стоит по умолчанию 0, при этом значении часто бывают тормоза. Во всех новых SQL его по умолчанию ставят на 60
https://sqlperformance.com/2020/05/system-configuration/0-to-60-switching-to-indirect-checkpoints
11. darminov 106 07.12.24 09:13 Сейчас в теме
(10) вы поднимали совместимость сервера или совместимость в конфигурации 1с?
12. roma_mef 14 07.12.24 09:20 Сейчас в теме
(11) Только сервера, ведь ее можно быстро переключить в обе стороны и без перестройки базы средствами 1с.
19. splxgf 10.12.24 08:38 Сейчас в теме
(8)
Повысьте режим совместимости и включите Query store
14. roma_mef 14 09.12.24 06:52 Сейчас в теме
(13) Я описал что нет проблем с обновлением статистики и скоростью ее выполнения. Я написал о проблеме "накопление" фрагментации и о том когда эту проблему уже не выходить заливать деньгами (мощностью сервере). База 20ТБ основные таблицы с которыми идет работа, около 1тб. Как решение еще можно рассмотреть партиционирование таблиц. Но не все таблицы можно разбить, и 1с не особо умеет работать с партициями
15. paulwist 09.12.24 11:55 Сейчас в теме
(14)
1с не особо умеет работать с партициями


Ммм, а покажите как 1С умеет работать партициями?

Выполнить задание перестройки по первой половине данных
Выполнить задание перестройки по второй половине данных


Из представленных скриптов перестроение индексов происходит "всего" на плюс/минус 2-х таблицах, это так задумано? (что бы на следующий день/ночь перестроить индексы ещё 2-х таблицах)
16. roma_mef 14 09.12.24 15:03 Сейчас в теме
(15)
Ммм, а покажите как 1С умеет работать партициями?
была раньше хорошая статья тут (которую странным образом потом удалили) и там был отличный пример, что 1с может как минимум делать неявное преобразование типов datetime (3) и в таком случае select будет идти по всей таблице игнорируя партиции.

(15)
Из представленных скриптов перестроение индексов происходит "всего" на плюс/минус 2-х таблицах, это так задумано? (что бы на следующий день/ночь перестроить индексы ещё 2-х таблицах)


с чего вы это решили? на первом шагу идет сбор всей статистики по индексам с заполнением таблицы с "флагом" 1 и 2. Затем во 2 и 3 шаге идет объявления курсора по всей таблице из первого шага с выборкой по флагу 1 для скрипта 2, флаг 2 для скрипта 3. и потом идет выполнение курсора по всем данным. Просто одновременно у вас выполняются 2 курсора со своими данными. И за раз делаются 2 таблицы. но это не значит что после этих 2х таблиц задание прекращается.
17. paulwist 09.12.24 16:30 Сейчас в теме
(16)
с чего вы это решили?


Смотрите.

-- Создадим табличку с 2-мя индексами

-- Для простоты предположим, что idx_f1 получил frag.num = 1, а idx_f2 получил frag.num = 2
-- то есть эти два индекса должны обработаться параллельно

-- Проверяем

use tempdb
go

cre ate   table t (f1 int, f2 int )
cre ate   index idx_f1 on t (f1)
cre ate   index idx_f2 on t (f2)
Показать


Там же выполним, ребилд первого индекса
begin tran
alt er   index [idx_f1] on t REBUILD WITH (ON LINE = ON)
sel ect * fr om sys.dm_tran_locks where resource_type in ( N'METADATA', 'KEY', N'OBJECT' )

-- Транзакцию не завершаем
-- Имитируем длительное выполнение индексирования
-- rollback
Показать


Открываем ещё одно соединение для индексации второго индекса, ведь хотим в параллельно переиндексировать.

use tempdb
go

begin tran
alt er   index [idx_f2] on t REBUILD WITH (ON LINE = ON)
rollback


Но не тут то было, висим.

Поэтому смотрим, что вернул первый запрос: а alt er index [idx_f1] on t REBUILD наложил монопольную блокировку намерений на всю таблицу и монопольную блокировку на индекс [idx_f1], поэтому второй сеанс висит не может переиндексировать второй индекс, поскольку он тоже хочет IX/X блокировку, которые несовместимы с первым сеансом.

В первом сеансе выполним rollback, что бы второй сеанс завершился.
Прикрепленные файлы:
18. roma_mef 14 09.12.24 17:13 Сейчас в теме
(17) Согласен что может попасть 2 индекса из одной таблицы на разные номера. Но не сказал бы что в данном примере это критично (но можно дописать еще одно условие, переход к следующему индексу и с возвратом потом к этому). Но даже без условия, у вас не будет остановки задания. я не встречал таких идеальных условий что бы все 50% на 50% было по одинаковым таблицам шло. И даже в таком случае если у вас попадет 2 индекса из одной таблицы, можно увеличить время ожидания на MAX_DURATION. 2 задание повесит с ожиданием, но когда 1 поток перейдет к пройдет к следующей таблице, переиндексация по 2му потоку пойдет на этом индексе.
20. paulwist 10.12.24 08:43 Сейчас в теме
(18)
я не встречал таких идеальных условий что бы все 50% на 50% было по одинаковым таблицам шло.


Табличек "жирных" немного, поэтому не сталкивались.

(18)
можно увеличить время ожидания


Смотрите, у вас два курсора создаются с одинаковым order by, те сначала в обоих случаях начинаются переиндексироваться наиболее фрагментированные таблички

order by ROUND ([fragmentation],0 ) desc, [rows_count] desc


Разнесите для второго курсора

order by ROUND ([fragmentation],0 ) ACS, [rows_count] ACS


что бы первый курсор шёл от сверху, второй снизу.

PS но если всё устраивает, то можно оставить как есть :)
roma_mef; +1 Ответить
21. roma_mef 14 10.12.24 11:16 Сейчас в теме
(20) Спасибо за замечание, мне не подойдет. Может кому-то кто будет использовать в дальнейшем скрипт будет полезно. Позже добавлю в статью ваше замечание.
22. webester 26 17.12.24 06:44 Сейчас в теме
Не совсем понятно, ola.hallengren.com не стали смотреть? Там вроде как и про паралельный запуск речь идет и про продолжение, если не успеваете в технологическое окно.
Оставьте свое сообщение