Для чистоты эксперимента я дождался нерабочего времени, когда сервер был полностью разгружен — никакие регламентные операции не выполнялись, — и запустил замер с помощью MS Profiler, отслеживая обмен пустыми пакетами.
К своему удивлению, обнаружил, что в проблемной базе обращения к таблице Config выполняются крайне медленно. Я начал сравнивать эту таблицу в нормальной и проблемной базе — оказалось, они различаются по размеру. Проблемная таблица была в 2 раза больше и содержала дубли. Дубли удалил, однако ситуация улучшилась лишь незначительно: значение Reads в Profiler сократилось вдвое, но оставалось аномально высоким, а обмен по-прежнему тормозил.
На втором этапе решил проверить индексы таблицы Config. Оказалось, что в проблемной базе вообще отсутствовал нужный индекс — вероятно, он «слетел» при появлении дублей, и механизмы 1С не смогли его автоматически восстановить. После создания индекса средствами SQL случилось долгожданное чудо: обмен стал занимать 3 секунды вместо 1 минуты!
А теперь — список запросов MS SQL, которые мне помогли:
1. Поиск дублей в таблице Config
-- Универсальный запрос для двух вариантов таблицы Config
-- 1. Для простых конфигураций, без поля PartNo
-- 2. Для больших конфигураций, где поле PartNo присутствует
DECLARE @sql NVARCHAR(MAX);
DECLARE @hasPartNo BIT;
-- Проверяем наличие столбца PartNo
SELECT @hasPartNo = CASE
WHEN EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Config' AND COLUMN_NAME = 'PartNo'
) THEN 1 ELSE 0 END;
-- Собираем SQL с учётом наличия PartNo
SET @sql = '
SELECT
Creation,
FileName,
Modified,
Attributes,
DataSize' +
CASE WHEN @hasPartNo = 1 THEN ', PartNo' ELSE '' END + ',
COUNT(*) AS Duplicates
FROM dbo.Config
GROUP BY
Creation,
FileName,
Modified,
Attributes,
DataSize' +
CASE WHEN @hasPartNo = 1 THEN ', PartNo' ELSE '' END + '
HAVING COUNT(*) > 1
ORDER BY Duplicates DESC;
';
-- Выполняем собранный SQL
EXEC sp_executesql @sql;
2. Проверка наличия индексов
SELECT
i.name AS IndexName,
i.type_desc AS IndexType,
c.name AS ColumnName,
ic.key_ordinal
FROM sys.indexes AS i
JOIN sys.index_columns AS ic
ON i.object_id = ic.object_id AND i.index_id = ic.index_id
JOIN sys.columns AS c
ON ic.object_id = c.object_id AND ic.column_id = c.column_id
WHERE i.object_id = OBJECT_ID('Config')
ORDER BY i.name, ic.key_ordinal;
3. Удаление дублей
DECLARE @sql NVARCHAR(MAX);
DECLARE @hasPartNo BIT;
-- Проверяем, есть ли поле PartNo в таблице Config
SELECT @hasPartNo = CASE
WHEN EXISTS (
SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Config' AND COLUMN_NAME = 'PartNo'
) THEN 1 ELSE 0
END;
-- Собираем список полей для PARTITION BY
DECLARE @partitionBy NVARCHAR(MAX) = '
Creation,
FileName,
Modified,
Attributes,
DataSize' +
CASE WHEN @hasPartNo = 1 THEN ', PartNo' ELSE '' END;
-- Собираем финальный запрос
SET @sql = '
WITH DuplicatesCTE AS (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY ' + @partitionBy + '
ORDER BY (SELECT NULL)
) AS RowNum
FROM dbo.Config
)
DELETE FROM DuplicatesCTE
WHERE RowNum > 1;
';
-- Выполняем
EXEC sp_executesql @sql;
4. Создаем индекс вручную
CREATE NONCLUSTERED INDEX IX_Config_FileName
ON Config(FileName);
p.s. Если кто знает, как можно проверить таблицу Config на дубли, удалить их и создать индекс средствами 1С, то буду очень признателен за информацию.
Вступайте в нашу телеграмм-группу Инфостарт