Кластерный индекс в базе 1С:Предприятия: как он устроен и почему от него зависит скорость

· 10 мин

Содержание

Кластерный индекс в 1С — это индекс таблицы базы данных, по ключу которого физически упорядочены сами строки таблицы. В клиент-серверной базе 1С 8.3 на MS SQL Server его создаёт платформа: разработчик в Конфигураторе не может ни назначить, ни отменить кластерный индекс. У каждой таблицы он один, и от его ключа зависит, насколько быстро СУБД найдёт запись по ссылке, прочитает движения документа и сколько строк заблокирует при записи.

Тема относится к платформе в целом, а не к конкретной конфигурации: одинаково для Бухгалтерии, ЗУП, УТ и ERP. Разница появляется только в выборе СУБД. В файловой базе такого понятия для администратора практически нет — управлять там нечем.

Как 1С хранит данные и зачем таблицам индексы

Каждый объект метаданных в серверной базе превращается в одну или несколько таблиц СУБД. Имена у них служебные:

  • 📁 _Reference25 — справочник;
  • 📄 _Document112 — шапка документа;
  • 📋 _Document112_VT1150 — табличная часть документа;
  • 📊 _AccumRg2045 — движения регистра накопления, _AccumRgT2056 — его итоги;
  • 🗂 _InfoRg1830 — регистр сведений .

Без индекса СУБД ищет нужную строку перебором всей таблицы. На справочнике из 500 записей это незаметно. На регистре с 40 млн движений такой перебор занимает секунды и минуты, а заодно держит блокировки и вытесняет из памяти полезный кеш.

Индекс — это отдельная упорядоченная структура (B-дерево), по которой СУБД за несколько шагов спускается к нужному ключу. Для таблицы в 40 млн строк хватает трёх-четырёх уровней дерева. Поэтому поиск по индексу читает десятки страниц, а не сотни тысяч.

Как узнать, какая таблица за каким объектом стоит

Соответствие имён удобно получить кодом на сервере:

&НаСервере
Процедура ПоказатьТаблицыНаСервере()
    Объекты = Новый Массив;
    Объекты.Добавить(Метаданные.Документы.РеализацияТоваровУслуг);
    Структура = ПолучитьСтруктуруХраненияБазыДанных(Объекты, Истина);
    Для Каждого Строка Из Структура Цикл
        Сообщить(Строка.ИмяТаблицыХранения + " — " + Строка.Назначение);
        Для Каждого Индекс Из Строка.Индексы Цикл
            Сообщить("    индекс: " + Индекс.ИмяИндексаХранения);
        КонецЦикла;
    КонецЦикла;
КонецПроцедуры

Второй параметр Истина возвращает имена так, как они записаны в СУБД, с подчёркиванием в начале. Эти имена потом ищут в планах запросов и в отчётах о фрагментации.

Кластерный и некластерный индекс: в чём разница

Главное отличие — где лежат данные строки.

ПризнакКластерныйНекластерный
Сколько на таблицуОдинМного
Что в листьях дереваСами строки таблицы целикомКлюч индекса и указатель на строку
Порядок хранения строкСовпадает с ключом индексаНе влияет на хранение
Чтение остальных полейСразу, без лишнего шагаНужен дополнительный поиск по кластерному ключу
Кто создаёт в 1СПлатформа, автоматическиПлатформа: свои + по свойству «Индексировать»

Кластерный индекс и есть таблица, отсортированная по ключу. Некластерный — это «оглавление» сбоку: найдя в нём ключ, СУБД переходит по кластерному ключу в основную таблицу за остальными полями. В плане запроса MS SQL этот переход виден как Key Lookup.

💡 Отсюда практическое следствие. Если некластерный индекс отбирает 10 строк — переход дешёвый. Если 300 тысяч — оптимизатор часто решает, что проще прочитать всю таблицу, и индекс по реквизиту не используется вовсе.

Что делает свойство «Индексировать»

У реквизитов, измерений и ресурсов в Конфигураторе есть свойство Индексировать с вариантами Не индексировать, Индексировать и Индексировать с доп. упорядочиванием. Оно всегда создаёт некластерный индекс. Сделать индекс по реквизиту кластерным средствами конфигурации нельзя.

Как кластерный индекс устроен в разных СУБД для 1С

MS SQL Server

Здесь кластерный индекс — полноценный механизм хранения. Для справочников и документов платформа строит его по полю ссылки _IDRRef: строка объекта лежит в дереве по своему 16-байтному идентификатору. Табличные части упорядочены по ссылке на владельца и служебному ключу строки, поэтому все строки одного документа хранятся рядом и читаются одним коротким диапазоном.

Для регистров ключ кластерного индекса включает период, регистратор или измерения — состав зависит от вида регистра и его настроек. Гадать не нужно, точный состав показывает запрос к системным представлениям:

SELECT t.name AS table_name, i.name AS index_name,
       c.name AS column_name, ic.key_ordinal
FROM sys.indexes i
JOIN sys.tables t ON t.object_id = i.object_id
JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id
JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
WHERE i.type_desc = 'CLUSTERED' AND t.name = '_AccumRg2045'
ORDER BY ic.key_ordinal;

Подставьте имя своей таблицы из предыдущего раздела. Колонка key_ordinal показывает порядок полей в ключе — он важнее самого набора полей.

PostgreSQL

В PostgreSQL кластерных индексов в понимании MS SQL нет. Таблица хранится «кучей», а все индексы, включая первичный ключ, отдельны от данных. Команда CLUSTER один раз переупорядочивает таблицу по индексу, но новые строки этот порядок не поддерживают.

Поэтому разговор о кластерном индексе для базы 1С на PostgreSQL сводится к другому: к актуальности статистики, раздуванию таблиц после массовых удалений и работе VACUUM. Индексы, которые строит платформа, те же по составу полей, но физика хранения иная.

Файловая база

В файловом варианте данные лежат в одном файле 1Cv8.1CD, и его внутреннюю организацию платформа ведёт сама. Отдельно управлять индексами нечем. Единственное, что доступно, — реиндексация через Конфигуратор → Администрирование → Тестирование и исправление.

Почему от кластерного ключа зависит скорость запросов 1С

Кластерный индекс выигрывает там, где нужно прочитать диапазон строк по началу ключа. Строки лежат рядом, СУБД читает несколько соседних страниц и не прыгает по диску.

Три типичных случая в 1С:

  1. 🔑 Получение объекта по ссылке. Открытие документа, обращение к реквизиту через точку — поиск по _IDRRef, то есть ровно по кластерному ключу. Один спуск по дереву, и строка у вас.
  2. 📋 Чтение табличной части. Все строки документа идут подряд в кластерном индексе табличной части. Даже документ на 2 000 строк читается быстро.
  3. 📆 Отбор движений по периоду или регистратору. Если условие запроса совпадает с началом ключа регистра, СУБД берёт узкий диапазон вместо полного просмотра.

Обратная сторона: условие по полю, которого нет в начале ключа, кластерный индекс не ускоряет. Индекс по полям «Период, Регистратор» не поможет отбору только по регистратору — СУБД всё равно придётся просмотреть всё.

Как это увидеть в плане запроса

В MS SQL Server Management Studio включите фактический план выполнения и посмотрите на операторы:

  • ✅ Clustered Index Seek — поиск по кластерному ключу, всё хорошо;
  • ⚠️ Clustered Index Scan — просмотр всей таблицы целиком, на больших таблицах это и есть тормоз;
  • 🔍 Index Seek + Key Lookup — поиск по некластерному индексу и добор полей из кластерного.

Текст запроса 1С в SQL виде можно получить из технологического журнала (событие DBMSSQL) или трассировкой SQL Server.

Что улучшает план со стороны конфигурации

  • 📌 Условия на измерения регистров передавайте в параметры виртуальной таблицы (Остатки(&Период, Номенклатура = &Товар)), а не в ГДЕ после соединения.
  • 📌 Не соединяйте с виртуальными таблицами напрямую там, где можно сначала отобрать данные во временную таблицу и проиндексировать её (ИНДЕКСИРОВАТЬ ПО).
  • 📌 Обращение к реквизитам через несколько точек порождает лишние соединения — получайте нужное поле явно.
  • 📌 Ставьте Индексировать на реквизит, только если по нему реально часто отбирают и он избирателен. Индекс на реквизите «Проведён» или «Пометка удаления» почти бесполезен.

Где кластерный индекс работает в документах и регистрах

ОбъектНа чём держится быстродействиеЧто замедляет
Справочник, документПоиск по ссылке через кластерный ключОтборы по неиндексированным реквизитам в списках
Табличная частьСтроки документа хранятся подрядПоиск документов по значению в табличной части
Регистр накопления (движения)Чтение и перезапись движений одного регистратораОтчёты с отбором по полю не из начала ключа
Регистр накопления (итоги)Быстрые остатки по измерениямОтключённые или неактуальные итоги
Регистр сведенийСрез последних по измерениям и периодуОтбор по ресурсу, а не по измерению

Мини-кейс: медленное проведение

Типичная картина: документ «Реализация» проводится 8–10 секунд, хотя раньше хватало секунды. В плане запроса проведения видно Clustered Index Scan по таблице движений регистра.

Причина обычно одна из двух. Либо в конфигурацию добавили отбор по полю, которого нет в начале ключа, либо статистика по таблице устарела и оптимизатор выбрал полный просмотр. Первое правит программист — переносит условие в параметры виртуальной таблицы или меняет состав измерений. Второе лечит администратор — обновлением статистики, о нём в следующем разделе.

Блокировки

В режиме управляемых блокировок на MS SQL СУБД блокирует строки и диапазоны в индексах. Когда запрос идёт по кластерному ключу, захватывается узкий диапазон. Когда идёт полный просмотр — блокировки могут укрупниться до всей таблицы, и пользователи начинают ждать друг друга. Поэтому медленный запрос с Clustered Index Scan часто проявляется не как «тормозит», а как ошибки ожидания блокировок у соседей.

Диагностика и обслуживание индексов базы 1С

Индексы со временем фрагментируются: страницы делятся при вставках в середину ключа, после удаления помеченных объектов остаются полупустые страницы. Плюс устаревает статистика — сведения о распределении значений, по которым оптимизатор выбирает план.

Проверка фрагментации в MS SQL

SELECT OBJECT_NAME(ips.object_id) AS table_name,
       i.name AS index_name, i.type_desc,
       ips.avg_fragmentation_in_percent, ips.page_count
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
JOIN sys.indexes i ON i.object_id = ips.object_id AND i.index_id = ips.index_id
WHERE ips.page_count > 1000
  AND ips.avg_fragmentation_in_percent > 10
ORDER BY ips.avg_fragmentation_in_percent DESC;

Запускайте в контексте нужной базы. Маленькие индексы (до 1 000 страниц) фильтр отсекает: их фрагментация на скорость не влияет.

Что делать с результатом

ФрагментацияДействиеКоманда
До 10%Ничего—
10–30%РеорганизацияALTER INDEX имя ON таблица REORGANIZE
Больше 30%ПерестроениеALTER INDEX имя ON таблица REBUILD

Пороги — ориентир, а не закон. На SSD-дисках фрагментация влияет меньше, чем раньше, и важнее регулярно обновлять статистику: UPDATE STATISTICS таблица или процедура sp_updatestats для всей базы.

Перестроение кластерного индекса перезаписывает всю таблицу. В редакции Standard оно идёт без опции ONLINE и блокирует таблицу на время работы — пользователи с этой таблицей ждут или получают ошибки блокировок. Запускайте перестроение ночью или в выходные, когда в базе нет пользователей.

Удобнее всего настроить всё один раз в плане обслуживания SQL Server: ежедневное обновление статистики и еженедельная реорганизация или перестроение индексов. Перед этим в том же плане должно стоять резервное копирование .

Обслуживание на PostgreSQL

Здесь основная работа — VACUUM ANALYZE (очистка «мёртвых» версий строк и обновление статистики). Обычно с этим справляется автовакуум, но после массовых операций, например удаления помеченных объектов или закрытия месяца, полезно запустить его вручную для крупных таблиц. Сильно раздутые индексы пересоздаются командой REINDEX; она тоже блокирует запись в таблицу, так что запускать её стоит вне рабочего времени.

Средствами 1С

В Конфигураторе есть Администрирование → Тестирование и исправление с флажком «Реиндексация таблиц информационной базы». Режим требует монопольного доступа, поэтому все пользователи должны выйти. Для серверной базы на MS SQL плановое обслуживание средствами СУБД гибче и быстрее, а этот режим уместен после сбоев.

Что у вас происходит с базой?

Когда кластерный индекс трогать не нужно

Соблазн «улучшить» индексы прямо в SQL возникает у многих. Делать этого не стоит:

  • 🚫 Свои индексы в SQL исчезают. При реструктуризации таблицы (после обновления конфигурации) платформа пересоздаёт её по своему описанию. Созданный вручную индекс пропадёт без предупреждения.
  • 🚫 Смена кластерного ключа ломает расчёт. Платформа и её запросы рассчитаны на свой порядок хранения. Изменённый вручную ключ может ускорить один отчёт и замедлить запись движений для всех.
  • 🚫 Перестроение не лечит плохой запрос. Если оптимизатор выбирает полный просмотр из-за условия на «чужое» поле, после перестроения индекса план останется тем же.

Правильный путь — менять структуру через Конфигуратор: свойство Индексировать у реквизита, порядок и состав измерений регистра, текст запроса. Тогда индексы будут жить столько же, сколько конфигурация.

Частые вопросы

Можно ли в 1С сделать кластерным индекс по своему реквизиту?
Нет. Свойство «Индексировать» создаёт только некластерный индекс. Кластерный ключ таблицы определяет платформа.
Почему у таблицы много индексов, хотя «Индексировать» нигде не стоит?
Часть индексов платформа строит сама: по ссылке, коду, наименованию, дате и номеру документа, периоду и регистратору регистров. Они нужны для работы списков и проведения.
Влияет ли порядок измерений регистра на индекс?
Да. Порядок измерений в Конфигураторе задаёт порядок полей в индексах регистра. Первыми ставят те измерения, по которым чаще всего отбирают данные.
Как часто перестраивать индексы базы 1С?
Для большинства баз хватает еженедельной реорганизации или перестроения и ежедневного обновления статистики. В небольших базах до нескольких гигабайт эффект от перестроения обычно незаметен.
Нужна ли выгрузка в .dt, чтобы пересоздать индексы?
Нет. На MS SQL и PostgreSQL индексы перестраиваются средствами СУБД при работающей базе, хотя и с блокировками. Выгрузка-загрузка .dt даёт тот же эффект, но требует монопольного доступа и занимает больше времени.