Не раз слышал мнения 1сников, что переиндексации вообще не нужна. Так как мы живем сейчас в век ssd и nvme. И не важно какая у вас фрагментация индекса нужно просто делать обновление статистики и все. И как подтверждение кидают абзац от Microsoft
Но почему – то не читают начало этой статьи, в которой сказано, как влияет фрагментация и плотность страниц на общую производительность. И расход ресурсов
И то что даже на ssd и NMVE последовательная скорость чтения запись всегда выше чем случайная
И про плотность, (если у вас конечно на сервере на 2ТБ памяти на базу 2ТБ)
Подытожим. Обновление статистики и правда даст вам сиюминутный эффект. Но со временем фрагментация сделает свое, и вам не хватает уже мощностей железа что бы перекрыть тормоза.
Так что мое мнение переиндексация нужна! Но не нужно каждый день перестраивать все индексы) Благо всевозможный скриптов хватает в сети.
Идея появилась из-за проблемы, что база в 20ТБ не могла за выделение тех окно пройти «полную» переиндексацию. И через неделю-две начинались дикие тормоза и обновление статистики не давало явного ускорения. Пробовал чужие скрипты с паузой и прочие. Но во всех скриптах перестройка индексов идет в один поток (я говорю не про maxdop). Что пока один индекс не перестроиться, другие не начнут. Так что вот представляю мой костыль)
Скрипт представляю в немного урезанном виде и на 2 потока.
Шаги в скрипте.
Собрать статистику по всем индексам в базе их фрагментации и размеру. Занести данные в служебную базу.
Выполнить задание перестройки по первой половине данных
Выполнить задание перестройки по второй половине данных
Обновить статистку, по все базе.
Шаги 2 и 3 выполняются параллельно.
Зачем, вы спросите, обновлять статистику по всей базе если переиндексация обновляет статистику? А я отвечу. Мы перестраиваем не все таблицы. А только что перестроенные индексы (при условии, что не было еще ни одной вставки) будут пропущены с сообщение, что нечего там обновлять. Это проще чем делать еще один шаг с условием. Что если переиндексация по таблице не проходила, то обнови статистику.
Можно все сделать разными 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 шаги почти идентичные кроме условия условий выбора и названия курсора.
2.
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
3.
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;
Если вдруг вы хотите добавить потоков, то необходимо будет в скрипте
Изменить параметр в SEQUENCE
Установить MAXVALUE на значение желаемых потоков
И создать шаг наподобие 2 или 3
Но тут нужно хорошо думать. Так как переиндексация достаточно сильно нагружаемый процесс. И можно поставить сервер колом если делать несколько alter index сразу.
После пары запусков с разными настройками удалось добиться 30% выигрыша по времени. И задание успевает выполниться за тех окно.
Комментарии (33)
generalx
06.12.2024 13:52хотел бы вас попросить сопровождение, на двух бд прошло успешно
на одной словил ошибкуExecuting query "SET QUOTED_IDENTIFIER ON; if DB_ID('profiler') ...".: 100% complete End Progress Error: 2024-12-07 08:57:34.52 Code: 0xC002F210 Source: Execute T-SQL Statement Task 1 Execute SQL Task Description: Executing the query "DECLARE @FramentationReportTable_1 VARCHAR(255) ..." failed with the following error: "Incorrect syntax near 'bad_indexes_1'.".
roma_mef Автор
06.12.2024 13:52Можно имя БД?
generalx
06.12.2024 13:52GoldenHome_Treasure_NEW_2012
roma_mef Автор
06.12.2024 13:52В базе профайлер таблицы с именами такого вида Fragmentation_GoldenHome_Treasure_NEW_2012дата ?
Вот этот запрос выдает результат или ошибку?
DECLARE @FramentationReportTable_1 VARCHAR(255)
SET @FramentationReportTable_1 = (SELECT top 1 table_name FROM Profiler.INFORMATION_SCHEMA.TABLES WHERE table_Name LIKE 'Fragmentation_GoldenHome_Treasure_NEW_2012'+REPLACE(convert(varchar, getdate(), 102), '.', '_') + '%')
print @FramentationReportTable_1exec ('
select
frag.db_name,
frag.schema_name,
frag.table_name,
frag.index_name,
frag.partition_num,
case
when frag.record_size16 <= 403 then 95 when frag.record_size16 <= 806 then 90
when frag.record_size*16 <= 1209 then 85
else 80
end as suggested_fillfactorfrom 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 frag.fragmentation desc')roma_mef Автор
06.12.2024 13:52Пока как предположение, без полного запроса. Что дата в таблице в базе profiler идет с датой от вчера. и по этому курсор не смог задаться (так как ищет от сегодня данные). Если это так то запрос должен выдать ошибку, и получить данные если будет SET @FramentationReportTable_1 = (SELECT top 1 table_name FROM Profiler.INFORMATION_SCHEMA.TABLES WHERE table_Name LIKE 'Fragmentation_GoldenHome_Treasure_NEW_2012'+REPLACE(convert(varchar, getdate()-1, 102), '.', '_') + '%')
generalx
06.12.2024 13:52Fragmentation_GoldenHome_Treasure_NEW_2012_2024_12_07_1
Msg 208, Level 16, State 1, Line 3
Invalid object name 'Profiler.dbo.frag'.roma_mef Автор
06.12.2024 13:52Ой я тогда в запросе, который кинул _ забыл после имени БД 'Fragmentation_GoldenHome_Treasure_NEW_2012_' нужно
generalx
06.12.2024 13:52база проблемная
Microsoft SQL Server 2017 (RTM) - 14.0.1000.169 (X64) Aug 22 2017 17:04:49 Copyright (C) 2017 Microsoft Corporation Standard Edition (64-bit) on Windows Server 2016 Standard 10.0 (Build 14393: ) (Hypervisor)обе где успешно
Microsoft SQL Server 2022 (RTM-CU11) (KB5032679) - 16.0.4105.2 (X64) Nov 14 2023 18:33:19 Copyright (C) 2022 Microsoft Corporation Standard Edition (64-bit) on Windows Server 2022 Standard 10.0 (Build 20348: ) (Hypervisor)все три разных хоста
generalx
06.12.2024 13:52Fragmentation_GoldenHome_Treasure_NEW_2012_2024_12_07_1
Msg 207, Level 16, State 1, Line 3
Invalid column name 'record_size16'.
Msg 207, Level 16, State 1, Line 3
Invalid column name 'record_size16'.Completion time: 2024-12-07T10:29:30.5579878+03:00
roma_mef Автор
06.12.2024 13:52Кажется в запросе где знаки потерялись при копирование у меня
DECLARE @FramentationReportTable_1 VARCHAR(255)
SET @FramentationReportTable_1 = (SELECT top 1 table_name FROM Profiler.INFORMATION_SCHEMA.TABLES WHERE table_Name LIKE 'Fragmentation_GoldenHome_Treasure_NEW_2012_'+REPLACE(convert(varchar, getdate(), 102), '.', '_') + '%')
print @FramentationReportTable_1exec ('
select
frag.db_name,
frag.schema_name,
frag.table_name,
frag.index_name,
frag.partition_num,
case
when frag.record_size*16 <= 403 then 95when frag.record_size*16 <= 806 then 90
when frag.record_size*16 <= 1209 then 85
else 80
end as suggested_fillfactorfrom 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 frag.fragmentation desc')
roma_mef Автор
06.12.2024 13:52А пришли, весь запрос который у тебя получился в скрипте, который не работает (насколько я понимаю это номер 2 должен быть что у меня в статье)
generalx
06.12.2024 13:52DECLARE @FramentationReportTable_1 VARCHAR(255)
SET @FramentationReportTable_1 = (SELECT top 1 table_name FROM Profiler.INFORMATION_SCHEMA.TABLES WHERE table_Name LIKE 'Fragmentation_GoldenHome_Treasure_NEW_2012_'+REPLACE(convert(varchar, getdate(), 102), '.', '_') + '%')
print @FramentationReportTable_1exec ('
DECLARE bad_indexes_1 CURSOR FORselect
frag.db_name,
frag.schema_name,
frag.table_name,
frag.index_name,
frag.partition_num,
case
when frag.record_size16 <= 403 then 95 when frag.record_size16 <= 806 then 90
when frag.record_size*16 <= 1209 then 85
else 80
end as suggested_fillfactorfrom 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_1DECLARE @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_STATUSS < 0 BREAK
IF @partition_num > 1
begin
SET @partitionOption = N' PARTITION=' + CAST@partition_numm AS nvarchar(10));
set @fillfactorOption = N''
end
else
begin
SET @partitionOption = N''
set @fillfactorOption = N' FILLFACTOR=' + CAST@suggested_fillfactorr as nvarchar(10)) + N', '
endSET @object_name = QUOTENAME@db_namee) + N'.' + QUOTENAME@schema_namee) + N'.' + QUOTENAME@table_namee)
BEGIN TRYSET @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@commandd, 0, 1)
EXEC@commandd)
set @time = CURRENT_TIMESTAMP;
RAISERROR(N'DONE', 0, 1)
END TRY
BEGIN CATCH
SET @command = N'ALTER INDEX ' + QUOTENAME@index_namee) + N' ON ' + @object_name + ' REBUILD ' + @partitionOption +' WITH(' + @fillfactorOption + N'maxdop = 0, SORT_IN_TEMPDB = ON)'
set @time = CURRENT_TIMESTAMP;
print @time
RAISERROR@commandd, 0, 1)
EXEC@commandd)
set @time = CURRENT_TIMESTAMP;
RAISERROR(N'DONE', 0, 1)
print @time
END CATCH
ENDclose bad_indexes_1
dealroma_mef Автор
06.12.2024 13:52Тоже смотрю у тебя часть запроса потерялась при копирование.
должно быть
IF @@FETCH_STATUS < 0 BREAK
а у тебя IF @FETCH_STATUSS < 0 BREAK
Кстати можешь попробовать на сервере выполнить запрос (корректный) просто закоментив обе строки с переиндексацией вот эти SET @command = N'ALTER INDEX ' .... и тогда будет проще увидеть где ошибка
generalx
06.12.2024 13:52Executed as user: NT Service\SQLSERVERAGENT. Microsoft (R) SQL Server Execute Package Utility Version 14.0.1000.169 for 64-bit Copyright (C) 2017 Microsoft. All rights reserved. Started: 12:32:42 PM Progress: 2024-12-07 12:32:43.29 Source: {3F75105D-FFED-468F-8903-4844FFB5DE7E} Executing query "DECLARE @Guid UNIQUEIDENTIFIER EXECUTE msdb..sp...".: 100% complete End Progress Progress: 2024-12-07 12:32:50.71 Source: Execute T-SQL Statement Task Executing query "SET QUOTED_IDENTIFIER ON; if DB_ID('profiler') ...".: 100% complete End Progress Error: 2024-12-07 12:32:50.76 Code: 0xC002F210 Source: Execute T-SQL Statement Task 2 Execute SQL Task Description: Executing the query "DECLARE @FramentationReportTable_2 VARCHAR(255) ..." failed with the following error: "Incorrect syntax near 'bad_indexes_2'.". Possible failure reasons: Problems with the query, "ResultSet" property not set correctly, parameters not set correctly, or connection not established correctly. End Error Error: 2024-12-07 12:32:50.76 Code: 0xC002F210 Source: Execute T-SQL Statement Task 1 Execute SQL Task Description: Executing the query "DECLARE @FramentationReportTable_1 VARCHAR(255) ..." failed with the following error: "Incorrect syntax near 'bad_indexes_1'.". Possible failure reasons: Problems with the query, "ResultSet" property not set correctly, parameters not set correctly, or connection not established correctly. End Error Warning: 2024-12-07 12:32:50.76 Code: 0x80019002 Source: Subplan_1 Description: SSIS Warning Code DTS_W_MAXIMUMERRORCOUNTREACHED. The Execution method succeeded, but the number of errors raised (2) reached the maximum allowed (1); resulting in failure. This occurs when the number of errors reaches the number specified in MaximumErrorCount. Change the MaximumErrorCount or fix the errors. End Warning DTExec: The package execution returned DTSER_FAILURE (1). Started: 12:32:42 PM Finished: 12:32:50 PM Elapsed: 8.078 seconds. The package execution failed. The step failed.
roma_mef Автор
06.12.2024 13:52Это больше похоже на ошибку из лога. Я имел ввиду new quary весь 2ой или 3й шаг из статьи на сервере выполнить. закометив строку с переиндексации.
generalx
06.12.2024 13:52Так ошибка в логах и не исполняет
я за коментил в скрипте2 ща во втором тоже сделаю
generalx
06.12.2024 13:52Msg 102, Level 15, State 1, Line 87
Incorrect syntax near 'bad_indexes_1'.Msg 102, Level 15, State 1, Line 87
Incorrect syntax near 'bad_indexes_2'.
roma_mef Автор
06.12.2024 13:52вот тут как раз написано в какой строке ошибка. нужно смотреть может где-то данные не передаются, или потерялся какой ни будь символ
generalx
06.12.2024 13:52Line 87 это конец скрипта. далее deal
я см. в notepad++ с отображением символов
generalx
06.12.2024 13:52скрипт отработал. спасибо за сопровождение. копировал через Ctr+a , почему образалось в оба скрипта с двух разных вкладок не ясно.
мое почтение.
Isiirk
06.12.2024 13:52А зачем вам успевать в техокно?, у меня самая большая база в терабайт сейчас, работает 2 скрипта, один занимается индексированием, второй сбором статистики, всё выполняется online, в скриптах для снижения нагрузки реализован механизм проверки, не выполняется ли сейчас бэкап в базе... Работает уже пол года, полет отличный, пару таблиц есть в базе, которые нельзя инлексировать online, но практика показывает, что проблем не возникает из за этого.
Индексация выполняется только тех, которые действительно надо, то же самое со статистикой, а не всё подряд
unfilled
06.12.2024 13:52А как ваш скрипт учитывает плотность страниц, о которой вы пишете в тексте? Ну, не считая того, что уменьшает её, уменьшая для всех таблиц fill factor?
roma_mef Автор
06.12.2024 13:52А зачем мне учитывать плотность страниц при перестройке индекса в общем случае без точной специфики работы базы. Ведь априори, если уменьшая фрагментацию, мы увеличиваем плотность данных на страницах. Вопрос изначальный в статье о том, что переиндексация нужна. А оставлять fill factor 0 чревато тем, что при любой вставке будет проходить разбиение и фрагментация будет расти слишком быстро. Но при этом и не желательно делать слишком много пустого пространства, из за которого плотность будет меньше. а общее условие
suggested_fillfactor
позволяет найти компромисс от полного заполнения станиц и как следствие каждодневное повышение фрагментации и сохранить плотность на должном уровне.
katamoto
А исходная проблема-то разрешилась? Т.е. обновление статистики не помогало, а теперь всё летает?
roma_mef Автор
Обновление статистики помогало только если день - два переиндексация не проходила. Если дольше то начинались тормоза. Сейчас (уже 3 месяца) переиндексация проходит каждую ночь и тормозов больше не наблюдается. Так что да, помогло решить исходную проблему.
katamoto
Обновление статистики так же каждую ночь делали?
roma_mef Автор
Да, каждую ночь. Но из-за фрагментация таблицы, самых больших таблиц уже не хватало железа что бы переварить запросы (типо всяких select'ов от начало времен). Был еще вариант заставить программистов 1с переделать их обработки, но они не захотели)