При проектировании высоконагруженных систем (например, логистических сервисов, почтовых служб или систем учета показаний) разработчики часто сталкиваются с необходимостью хранить сотни миллионов записей в независимых непериодических регистрах сведений. Главный вопрос заключается в том, как правильно выбрать тип ключевого поля (трек-номера или идентификатора события), стоит ли использовать тип УникальныйИдентификатор, нужно ли включать явную индексацию для таких измерений и как обеспечить максимальную скорость чтения и записи в СУБД MS SQL.
Разберем подробно технические особенности работы платформы 1С и СУБД с уникальными идентификаторами, проанализируем правила индексации и рассмотрим оптимальные архитектурные решения.
Рассмотрим, как платформа 1С формирует индексы для независимого регистра сведений. Очень часто разработчики включают свойство Индексировать у единственного или первого измерения регистра, полагая, что это ускорит поиск.
В платформе 1С действует строгое правило формирования структуры таблиц СУБД:
Проанализируем две архитектурные модели: использование одного поля типа УникальныйИдентификатор либо пары полей (строковый префикс и порядковый номер).
УникальныйИдентификатор в СУБД MS SQL физически хранится как бинарное поле binary(16) и занимает ровно 16 байт. Составной ключ из строки (например, NVARCHAR(30), занимающий до 60 байт) и числа (NUMERIC, от 5 до 9 байт) требует значительно больше дискового пространства. Чем компактнее индекс, тем больше строк помещается на одну 8-килобайтную страницу данных в оперативной памяти (Buffer Pool), что напрямую снижает нагрузку на дисковую подсистему ввода-вывода (I/O).ПО при объединении таблиц в запросах.Выясним, с какими системными особенностями можно столкнуться при использовании типа УникальныйИдентификатор в прикладных решениях:
8.3.12 (или при включенном режиме совместимости 8.3.11 и ниже) существовало жесткое ограничение: поля типа УникальныйИдентификатор нельзя было помещать во временные таблицы при передаче таблицы значений в качестве параметра запроса. Начиная с версии платформы 8.3.12.1159, поддержка данного типа была расширена — появилась возможность создавать временные таблицы из таблиц значений с такими колонками и использовать их в условии В.УникальныйИдентификатор не предусмотрено стандартное пользовательское представление, по ним невозможно настроить полнотекстовый поиск платформы, а стандартная сортировка в запросах упорядочивает их по бинарному значению, а не по алфавиту строкового представления.УникальныйИдентификатор может быть недоступен программно или интерактивно, в отличие от ссылочных типов.Если для хранения данных выбран независимый регистр сведений, критически важно правильно реализовать запись. Использование объекта РегистрСведенийМенеджерЗаписи для миллионов строк неприемлемо, так как на каждую строку инициируется отдельное чтение и запись с избыточными блокировками.
Правильный подход — пакетная запись порциями с использованием объекта РегистрСведенийНаборЗаписей:
// Пример пакетной записи набора данных
НаборЗаписей = РегистрыСведений.ИсторияОтправлений.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ИдентификаторОтправления.Установить(Идентификатор);
// Если измерение заведомо уникально и отбор не накладывается на весь регистр,
// выполняем запись без чтения существующих данных порциями
НаборЗаписей.Записывать = Истина;
Для Каждого СтрокаДанных Из МассивНовыхДанных Цикл
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ИдентификаторОтправления = СтрокаДанных.ГУИД;
НоваяЗапись.Состояние = СтрокаДанных.Статус;
НоваяЗапись.ДатаСобытия = СтрокаДанных.Дата;
КонецЦикла;
// Отключаем замещение для прямой вставки новых строк
НаборЗаписей.Записать(Ложь);
Когда объемы таблицы превышают десятки миллионов записей, регистр сведений не всегда является лучшим выбором. Рассмотрим альтернативы:
ОБЪЕДИНИТЬ ВСЕ.