Дата последнего изменения: 09.11.2023
При создании информационных блоков рекомендуется хранить свойства инфоблока в отдельной таблице, причем все значения свойств одного элемента хранятся в одной строке. Эта технология называется Инфоблоки 2.0 В документации к Bitrix Framework, в сообщениях форума на сайте компании и в других местах могут встречаться прежние названия технологии: инфоблоки +. и позволяет существенно ускорить работу системы, а также снять ряд ограничений в предыдущей версии инфоблоков. Например, теперь нет необходимости в дополнительном запросе CIBlockElement::GetProperty при выборе значений свойств функцией CIBlockElement::GetList.
Возможности инфоблоков 2.0:
IBLOCK_ID
.Важным является полная совместимость API. То есть техника использования инфоблоков, свойств, элементов и их значений одинакова для обоих версий инфоблоков.
Для разработчика очень удобно и гибко то, что свойства хранятся в одной общей таблице и управляются информацией метаданных из IBLOCK_PROPERTY_ID
. Так как всегда можно поправить какую-то метаинформацию и никакая другая информация при этом у вас не пропадет. Это свойственно простым инфоблокам.
Если информация хранится в инфоблоках 2.0 и у свойства меняется его тип (например, с Числа на Строку), то изменяется и тип хранения в самой базе данных. То есть меняется не логика интерпретации продуктом значения этого свойства, а меняется само значение. То есть нельзя "играться" с данными.
С точки зрения производительности инфоблоки 2.0 выигрывают на небольших справочниках с небольшим количеством (20-30) редко изменяемых свойств. Ленту новостей нет никакого смысла переводить на этот вид инфоблоков. Вы выиграете в числе запросов, но проиграете во времени их исполнения.
В инфоблоках 2.0 существует физическое ограничение БД на количество свойств инфоблока. На данный момент это не отслеживается в системе, так как зависит от множества непрогнозируемых факторов: типа свойств, конфигурации MySQL и других. При превышении этого физического ограничения вы получите редкую для Bitrix Framework ошибку MySQL. Данные при этом потеряны не будут.
Большое преимущество инфоблоков 2.0 – возможность использования составных индексов. Однако достаточно редка ситуация, когда выполняется фильтр по = и по нескольким полям одновременно.
У информационного блока есть признак VERSION
, который при создании нового инфоблока определяет выбор хранения значений свойств информационного блока в общем хранилище или в выделенном. При выборе выделенного хранения для данного инфоблока в БД создаются две дополнительные таблицы, включающие в своё имя идентификатор инфоблока. В одной из них будут храниться множественные свойства, а в другой единичные и кешированные значения множественных.
При редактировании инфоблока доступна ссылка на "конвертер" между типами хранения. Пользоваться им надо с большой осторожностью, т.к. продолжительность процесса конвертации зависит от общего объема значений свойств инфоблока. В течение всего процесса инфоблок находится в несогласованном состоянии (часть значений перенесена, а часть нет). На тестовой конфигурации для MySQL версии скорость была порядка 1500 элементов за 20-ти секундный шаг.
В классе CIBlockResult переопределён метод Fetch. В нем происходит кеширование значений множественных свойств элемента, участвующих в выборке. Для этих же свойств типа список выбираются пары ID=>VALUE из справочника списков.
В API предусмотрен параметр VERSION
в массиве полей $arFields
метода CIBlock::Add. Его значения: 1 - для общего хранения и 2 - для выделенного (нового).
При редактировании свойств (смена признака множественности или типа свойства) для свойств в выделенном хранилище выполняются дополнительные операции по управлению таблицами. Такие как удаление/добавление колонок, вставка/обновление или удаление большого количества записей. Без настоятельной необходимости лучше избегать этого. Наилучшей методикой будет менять тип или множественность одного свойства за один раз. Причем для единичных свойств предпочтительнее сначала сделать его множественным а потом сменить тип, а для множественных наоборот - сначала тип, и уже потом делать его единичным.
При вставке элемента вставляется и соответствующая запись в таблицу хранения значений свойств элемента.
Значения единичных свойств инфоблока с выделенным хранилищем ID - составные и состоят из ID элемента и ID свойства, разделенных двоеточием. При обновлении множественных свойств происходит сброс кеша этих значений.
Значения свойств хранятся в 2-х таблицах (описание таблиц и их структуры имеет справочный характер и могут меняться в следующих версиях):
IBLOCK_ELEMENT_ID
- ID элемента инфоблока которому принадлежат свойства:
Для использования преимуществ, создаваемых структурой хранения данных в новых инфоблоках, необходимо несколько модифицировать логику работы компонентов.
Например: если раньше шаблон кода был примерно таким:
<? //Определяем массив нужных полей элемента $arSelect = array( "ID", "IBLOCK_ID", "IBLOCK_SECTION_ID", "NAME", "PREVIEW_PICTURE", "DETAIL_PICTURE", "DETAIL_PAGE_URL", ); //Получаем список элементов. (+1 запрос) if($rsElements = GetIBlockElementListEx($IBLOCK_TYPE, false, false, array($ELEMENT_SORT_FIELD => $ELEMENT_SORT_ORDER), $ELEMENT_COUNT, $arFilter, $arSelect)) { //Инициализация постраничного вывода. $rsElements->NavStart($ELEMENT_COUNT); $count = intval($rsElements->SelectedRowsCount()); if ($count>0) { //Для каждого элемента: while ($obElement = $rsElements->GetNextElement()) { $arElement = $obElement->GetFields(); //Получаем его свойства. (+1 запрос) $arProperty = $obElement->GetProperties(); //Ниже можно пользоваться значениями свойств. //Например: echo $arProperty["SOURCE"],"
"; //и т.д. и т.п. } } } ?>
Теперь, после преобразования в новый тип хранения, стало возможным избавится от запросов в цикле:
<? //Определяем массив нужных полей элемента $arSelect = array( "ID", "IBLOCK_ID", "IBLOCK_SECTION_ID", "NAME", "PREVIEW_PICTURE", "DETAIL_PICTURE", "DETAIL_PAGE_URL", "PROPERTY_SOURCE", //Выбираем нужное нам свойство // И все другие какие могут понадобится // непосредственно в списке ); //Получаем список элементов. (+1 запрос) if($rsElements = GetIBlockElementListEx($IBLOCK_TYPE, false, false, array($ELEMENT_SORT_FIELD => $ELEMENT_SORT_ORDER), Array("nPageSize"=>$ELEMENT_COUNT), $arFilter, $arSelect)) { //Инициализация постраничного вывода. $rsElements->NavStart($ELEMENT_COUNT); if($obElement = $rsElements->GetNextElement()) { //Для каждого элемента: do { $arElement = $obElement->GetFields(); //Ниже можно пользоваться значениями свойств. //Например: echo $arElement["PROPERTY_SOURCE"],"
"; //и т.д. и т.п. } while ($obElement = $rsElements->GetNextElement()) } } ?>