Перейти к содержимому

Хранение свойств инфоблока - две версии, скорость, выбор режима

Разбираем два режима хранения свойств инфоблока: где лежат значения, как это влияет на выборки и дубли строк и когда режим стоит переключать.

Механика

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

В первом режиме все значения лежат в одной общей таблице значений свойств. Каждое значение занимает свою строку, и выборка элементов со свойствами превращается в соединение с этой большой таблицей.

Во втором режиме у каждого инфоблока появляются собственные таблицы значений. Единичные свойства ложатся колонками в одну таблицу, а множественные живут в отдельной, парной к ней.

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

Общая таблица даёт дубли строк при множественных свойствах. Элемент с тремя значениями свойства возвращается тремя строками, и ограничение на число записей считает именно строки, а не элементы.

Второй режим не бесплатен и не универсален. При нескольких десятках свойств таблица инфоблока становится широкой, а правка структуры свойств - заметно более дорогой операцией.

Переключение режима перестраивает хранение всех значений инфоблока. На большом каталоге это долгая операция, и её делают на копии, а потом повторяют на бою в тихое время.

Режим влияет и на доступные интерфейсы работы со свойствами. Часть объектного интерфейса свойств рассчитана на первый режим, поэтому смену режима проверяют вместе со своим кодом.

Шаги

  1. Посмотреть текущий режим хранения свойств у нужного инфоблока в его настройках.
  2. Оценить число свойств: до полусотни второй режим обычно выигрывает по скорости.
  3. Проверить свой код на выборки, которые опираются на дубли строк выборки.
  4. Переключить режим на копии сайта и замерить скорость витрины до и после.
  5. Повторить переключение на боевом сайте в тихое время и сбросить кэш витрины.

Код

Смотрим режим хранения и число свойств:

$iblock = \CIBlock::GetByID($iblockId)->Fetch();
printf("режим=%s свойств=%d\n", $iblock['VERSION'],
\CIBlockProperty::GetList([], ['IBLOCK_ID' => $iblockId])->SelectedRowsCount());
// режим 1 - общая таблица значений, режим 2 - собственные таблицы инфоблока

Число свойств решает вопрос выбора почти без обсуждения. Полтора десятка свойств на карточке товара - это второй режим, а сотня разнородных полей уже требует разговора о самой структуре данных.

Смотрим, где физически лежат значения:

SHOW TABLES LIKE 'b_iblock_element_prop_s%'; -- таблицы единичных свойств
SHOW TABLES LIKE 'b_iblock_element_prop_m%'; -- таблицы множественных свойств
-- номер в имени таблицы совпадает с идентификатором самого инфоблока
SELECT COUNT(*) FROM b_iblock_element_property; -- общая таблица первого режима

Наличие таблиц с номером инфоблока сразу показывает выбранный режим. Это удобнее чтения настроек: на живом проекте инфоблоков десятки, и режимы у них нередко разные.

Ловим дубли строк на множественном свойстве:

$res = \CIBlockElement::GetList([], ['IBLOCK_ID' => $iblockId], false,
['nTopCount' => 10], ['ID', 'NAME', 'PROPERTY_COLORS']);
$ids = [];
while ($row = $res->Fetch()) { $ids[] = $row['ID']; }
printf("строк=%d уникальных элементов=%d\n", count($ids), count(array_unique($ids)));

Расхождение этих двух чисел и есть тот самый дубль строк. Ограничение на число записей при этом обрезает выборку по строкам, и на витрину попадает меньше товаров, чем ожидает шаблон.

Забираем свойства отдельным запросом:

$props = [];
$res = \CIBlockElement::GetPropertyValues($iblockId, ['ID' => $ids], true);
while ($row = $res->Fetch()) { $props[$row['IBLOCK_ELEMENT_ID']] = $row; }
// свойства одной выборкой по списку идентификаторов вместо запроса на элемент

Отдельная выборка свойств по списку идентификаторов одинаково работает в обоих режимах. Это универсальный приём: список элементов забирается одним запросом, свойства - вторым, и дубли строк при этом никого не беспокоят.

Приём заодно упрощает кэширование результата на витрине. Список и свойства кэшируются вместе, а ключ кэша собирается из раздела, страницы и параметров фильтра, а не из внутренностей выборки.

Считаем объём значений свойств инфоблока:

SELECT COUNT(*) AS values_count FROM b_iblock_element_property
WHERE IBLOCK_PROPERTY_ID IN (SELECT ID FROM b_iblock_property WHERE IBLOCK_ID = 5);
-- в первом режиме это число растёт как число элементов, умноженное на свойства

Объём значений объясняет, почему выборка со свойствами дорожает быстрее самого каталога. Десять тысяч товаров с двадцатью свойствами дают двести тысяч строк, и каждая выборка витрины идёт по ним.

Переключаем режим хранения из кода:

$iblock = new \CIBlock();
$iblock->Update($iblockId, ['VERSION' => 2]); // перестройка хранения значений
printf("ошибка: %s\n", $iblock->LAST_ERROR ?: 'нет');
// на большом каталоге операция долгая: запускают ночью и на копии сначала

Переключение выполняется одной строкой, но работает долго. Перед запуском на бою снимают резервную копию и проверяют, что обмен с учётной системой в это время не стартует по расписанию.

Замеряем скорость до и после переключения:

$start = microtime(true);
\CIBlockElement::GetList([], ['IBLOCK_ID' => $iblockId], false, ['nTopCount' => 100],
['ID', 'NAME', 'PROPERTY_*'])->Fetch();
printf("выборка со свойствами: %.3f c\n", microtime(true) - $start);
// замер повторяют на копии до переключения режима и сразу после него

Ограничения

Переключение режима - долгая операция на большом каталоге. Пока идёт перестройка, инфоблок лучше не трогать ни обменом, ни редакцией, а на витрине держать предыдущий кэш.

Второй режим плохо переносит сотни свойств у одного инфоблока. Широкая таблица медленно меняется при добавлении свойств, а обмен с учётной системой начинает упираться в структуру.

Часть готовых решений рассчитана на конкретный режим хранения. Перед переключением проверяют сторонние модули каталога: не все из них одинаково работают в обоих режимах.

Режим не решает проблему плохих выборок в прикладном коде. Запрос свойств в цикле по товарам останется медленным в любом режиме, и его правят раньше, чем трогают хранение значений.

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

Наконец, режим хранения не виден редакции и не влияет на интерфейс. Для контент- менеджера всё остаётся прежним, поэтому объяснять ему смену режима не требуется вовсе.

Типичные проблемы

На витрину попадает меньше товаров, чем задано в параметрах.

Множественные свойства дублируют строки выборки, а ограничение считает строки. Свойства забирают отдельным запросом по списку идентификаторов элементов.

Каталог с большим числом свойств стал медленным.

Все значения лежат в общей таблице, и выборка соединяется с ней на каждый показ. Для каталога с десятком свойств выигрывает режим собственных таблиц.

После переключения режима часть кода перестала работать.

Код опирался на интерфейсы, рассчитанные на прежний режим хранения значений. Свой код проверяют на копии до переключения боевого сайта.

Переключение режима повесило сайт на полчаса.

Перестройка хранения запущена на боевом сайте в рабочее время без подготовки. Такие операции делают ночью и после проверки на копии.

Добавление нового свойства стало долгим.

У инфоблока сотни свойств во втором режиме, и таблица перестраивается целиком. Структуру пересматривают: часть данных выносят в отдельный справочник.

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

Какой режим выбрать для нового каталога?

Для обычного каталога с десятком-двумя свойств берут режим собственных таблиц. Он быстрее на выборках и не даёт дублей строк по множественным свойствам.

Меняется ли прикладной код при смене режима?

Нет, методы выборки и записи одинаковы в обоих режимах. Меняется только устройство таблиц и скорость запросов под капотом.

Можно ли вернуть прежний режим обратно?

Да, переключение работает в обе стороны и данные не теряются. Но это снова долгая перестройка, поэтому режим выбирают осознанно.

Сколько свойств считается много?

Ориентир - несколько десятков на инфоблок. Дальше стоит думать не о режиме хранения, а о разделении данных между инфоблоком и справочниками.

Влияет ли режим на обмен с учётной системой?

Скорость обмена меняется вместе со скоростью записи свойств. Сам формат обмена и коды свойств от режима не зависят.

Смежное

Первоисточник