Bitrix Site Manager

Storing properties in dedicated tables

Introduction

Since version 5.1, developers can choose how and where the properties of an information block element are located. Properties can now be stored in dedicated tables, and all property values of an element can be saved in a single row. The following notes should be taken into consideration.

  1. When selecting elements, property values can be obtained immediately because the count of tables does not increase and is always 1.
  2. The same rule apply to filtering by property values (with the exception of multiple properties).
  3. Fetching values of multiple properties now does not result in Cartesian multiplication of query results - property values are passed in an array.
  4. For complex filters with simple (not multiple) properties, the database aggregative index can now be created manually for faster selection operations.
  5. For information blocks that store property values in dedicated tables, elements cannot be selected transparently (with the filter set to an information block type and a property symbolic code). IBLOCK_ID has to be specified in the filter.

API remains fully compatible. You can use the same programming approaches as before. However, you can take advantage of the new techniques: for example, calling  CIBlockElement::GetProperty is now redundant after obtaining property values using CIBlockElement::GetList.

Information blocks

Information blocks now have a new field: VERSION. This allows developers to choose the type of storage for information block property values: in a public or dedicated storage. In the latter case, two new tables are created for an information block in the database; the names of these tables include the information block ID. One of the tables store multiple properties, the other one stores simple and cached values of multiple properties.

The information block editing form displays a link that activates the storage type converter. Use extreme care with this feature, since the duration of conversion depends on the amount of property values. During conversion, the information block is in unstable state because some values are converted but some are not. A test MySQL configuration indicated speed of 1500 elements per 20 second step.

The class CIBlockResult now overrides Fetch. It now caches values of obtained multiple properties. For the "list" properties, it selects pairs ID=>VALUE from the list dictionary.

An array of fields ($arFields) of CIBlock::Add now supports the "VERSION" field . It can be 1 - for public storage and 2 - for dedicated storage.

Information block properties

There are no changes to information block properties in the administration interface, nor in the Control Panel.

When editing properties (toggling the "Multiple" flag or changing the property type), additional support operations are performed in the dedicated storages. These include adding/deleting columns, insertion, removal or updating of many records. You should avoid editing dedicated properties if possible. The best practice would be to change the type or the "multiple" flag at a single run. For simple properties, the best order of operations is to make them multiple and then change the type. For multiple properties, change the type and then make them simple.

Information block elements

The major changes occurred to the GetList method. These changes was highlighted in the Introduction.

When an element is added, a corresponding record is added to a table that stores values of element properties.

Values of information block element properties

The ID's of values of simple properties of dedicated information blocks are synthetic. It consists of ID's of an element and a property separated with colon (:).

When a multiple property is updated, the cache is reset.

Property values are stored in 2 tables. The table description is for reference only and is subject to change:

Power use of new information blocks. Programming techniques

To take advantages that a new storage structure can give, you have to alter the programming logic of components.

For example: consider a piece of an old-fashioned code:


<?
// Define an array of the required fields
$arSelect = array(
    "ID",
    "IBLOCK_ID",
    "IBLOCK_SECTION_ID",
    "NAME",
    "PREVIEW_PICTURE",
    "DETAIL_PICTURE",
    "DETAIL_PAGE_URL",
);

// Get the list of elements (+1 query)
if($rsElements = GetIBlockElementListEx($IBLOCK_TYPE, 
                                        false, false, 
                                        array($ELEMENT_SORT_FIELD => $ELEMENT_SORT_ORDER), 
                                        $ELEMENT_COUNT, 
                                        $arFilter, $arSelect))
{
    // Initialise pagewise display.
    $rsElements->NavStart($ELEMENT_COUNT);
    $count = intval($rsElements->SelectedRowsCount());
    if ($count>0)
    {
        // For each element:
        while ($obElement = $rsElements->GetNextElement())
        {
            $arElement = $obElement->GetFields();

            // Obtain element properties (+1 query)
            $arProperty = $obElement->GetProperties();

            // Now we can use property values
            // example:
            echo $arProperty["SOURCE"],"<br>";
            // etc.
        }
    }
}
?>

Now, having converted to a new storage mode, we can avoid requests in loops:


<?
// Define an array of the required fields
$arSelect = array(
    "ID",
    "IBLOCK_ID",
    "IBLOCK_SECTION_ID",
    "NAME",
    "PREVIEW_PICTURE",
    "DETAIL_PICTURE",
    "DETAIL_PAGE_URL",
    "PROPERTY_SOURCE", // Specify the required property
    // ...                and any other that we may need
    // ...                right here!
);

// Get the list of elements (+1 query)
if($rsElements = GetIBlockElementListEx($IBLOCK_TYPE, 
                                        false, false, 
                                        array($ELEMENT_SORT_FIELD => $ELEMENT_SORT_ORDER), 
                                        Array("nPageSize"=>$ELEMENT_COUNT), 
                                        $arFilter, $arSelect))
{
    // Initialise pagewise display.
    $rsElements->NavStart($ELEMENT_COUNT);
    if($obElement = $rsElements->GetNextElement())
    {
        // Do for each element:
        do
        {
            $arElement = $obElement->GetFields();

            // Now we can use property values
            // example:
            echo $arElement["PROPERTY_SOURCE"],"<br>";
            // etc.
        }
        while ($obElement = $rsElements->GetNextElement())
    }
}
?>