Кластерный индекс в базе 1С:Предприятия: как он устроен и почему от него зависит скорость
Содержание
Кластерный индекс в 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С:
- 🔑 Получение объекта по ссылке. Открытие документа, обращение к реквизиту через точку — поиск по
_IDRRef, то есть ровно по кластерному ключу. Один спуск по дереву, и строка у вас. - 📋 Чтение табличной части. Все строки документа идут подряд в кластерном индексе табличной части. Даже документ на 2 000 строк читается быстро.
- 📆 Отбор движений по периоду или регистратору. Если условие запроса совпадает с началом ключа регистра, СУБД берёт узкий диапазон вместо полного просмотра.
Обратная сторона: условие по полю, которого нет в начале ключа, кластерный индекс не ускоряет. Индекс по полям «Период, Регистратор» не поможет отбору только по регистратору — СУБД всё равно придётся просмотреть всё.
Как это увидеть в плане запроса
В 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 исчезают. При реструктуризации таблицы (после обновления конфигурации) платформа пересоздаёт её по своему описанию. Созданный вручную индекс пропадёт без предупреждения.
- 🚫 Смена кластерного ключа ломает расчёт. Платформа и её запросы рассчитаны на свой порядок хранения. Изменённый вручную ключ может ускорить один отчёт и замедлить запись движений для всех.
- 🚫 Перестроение не лечит плохой запрос. Если оптимизатор выбирает полный просмотр из-за условия на «чужое» поле, после перестроения индекса план останется тем же.
Правильный путь — менять структуру через Конфигуратор: свойство Индексировать у реквизита, порядок и состав измерений регистра, текст запроса. Тогда индексы будут жить столько же, сколько конфигурация.