1С-Битрикс. Ускоряем выборку в модуле «Информационные блоки» с помощью GetList в 10 раз
При разработке очередного интернет-магазина на 1С-Битрикс, нужно было вывести горизонтальное меню, состоящее из >250 категорий каталога. В Битриксе с этим проблем нет. Подключаем компонент menu.sections и получаем массив пунктов меню в нужном формате для компонента menu.
Но если выключить кеш и включить отладку, то увидим что компонент формирует >250 SQL запросов. Конечно, когда будет включен кеш на сайте, столько не будет и всё будет браться из кэша.
Но всё таки, когда будет сбрасываться кеш, это будет ощутимо. Попробуем разобраться в чем же дело.
Идем в компонент и видим, что категории выбираются функцией CIBlockSection::GetList, которая возвращает CIBlockResult. Далее функцией CIBlockResult::GetNext получаем список полей. GetNext возвращаем элементы, приведенные в HTML безопасный вид и так же преобразует в DETAIL_PAGE_URL, SECTION_PAGE_URL в реальные урлы элементов и категорий.
Тут-то и оно, если добавить в выборку SECTION_PAGE_URL, то на каждую категорию для постраения урла будет сделано столько подзапросов, сколько категорий.
Проверим на практике.
CIBlockSection::GetList и GetNext
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php"); // подключаем модуль «Информационные блоки» CModule::IncludeModule('iblock'); // определяем настройки $arParams = array( 'IBLOCK_ID' => 2, ); $sections = array(); $resCatalog = CIBlockSection::GetList( array( 'LEFT_MARGIN' => 'ASC' ), array( 'IBLOCK_ID' => $arParams['IBLOCK_ID'], 'ACTIVE' => 'Y', 'GLOBAL_ACTIVE' => 'Y', ), false, array( 'IBLOCK_ID', 'IBLOCK_SECTION_ID', 'NAME', 'SECTION_PAGE_URL', 'UF_*' ) ); while($arCatalog = $resCatalog->GetNext()){ $sections[$arCatalog['ID']] = $arCatalog; }
Включаем отладку в битриксе и видим кучу таких запросов:
SELECT IBLOCK_ID, CODE FROM b_iblock_section WHERE ID = 213; SELECT BS.ID AS ID, BS.IBLOCK_SECTION_ID AS IBLOCK_SECTION_ID, BS.CODE AS CODE FROM b_iblock_section BS INNER JOIN b_iblock B ON B.ID = BS.IBLOCK_ID WHERE BS.ID=213 AND BS.IBLOCK_ID=2;
Лог: Получаем: 0.2510; Запросов: 252
CIBlockSection::GetList и Fetch
Попробуем выкинуть из выборки SECTION_PAGE_URL и построить урлы с помощью своего способа без подзапросов.
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php"); // подключаем модуль «Информационные блоки» CModule::IncludeModule('iblock'); // определяем настройки $arParams = array( 'IBLOCK_ID' => 2, ); // сюда будем складывать все категории global $sections; // этой функцией будем стоить урл function makeUrl($parentId = 0){ global $sections; $sefFolder = '/katalog/'; $codes = array(); while (isset($parentId)) { $codes[] = $sections[$parentId]['CODE']; if(isset($sections[$parentId])){ $parentId = $sections[$parentId]['IBLOCK_SECTION_ID']; }else{ $parentId = null; } } if (sizeof($codes)) { return $sefFolder . implode('/', array_reverse($codes)); } else { return null; } } $sections = array(); $resCatalog = CIBlockSection::GetList( array( 'LEFT_MARGIN' => 'ASC' ), array( 'IBLOCK_ID' => $arParams['IBLOCK_ID'], 'ACTIVE' => 'Y', 'GLOBAL_ACTIVE' => 'Y', ), false, array( 'IBLOCK_ID', 'IBLOCK_SECTION_ID', 'NAME', 'SECTION_PAGE_URL', 'UF_*' ) ); while($arCatalog = $resCatalog->Fetch()){ $sections[$arCatalog['ID']] = $arCatalog; } foreach($sections as &$section){ $section['SECTION_PAGE_URL'] = makeUrl($section['ID']); }
Получаем: 0.0263 с; Запросов: 1
Результат
Не делая лишних подзапросов, и заменив GetNext на Fetch мы получили прирост в скорости в 10 раз.