Запросы в цикле в стандартных компонентах или хватит это терпеть

Рейтинг: 12.4783  
На голосовании
Предложил Ерофеев Анатолий 12.09.2013 08:55:46

Запросы в цикле в стандартных компонентах или хватит это терпеть

Идея

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

Кому и зачем нужно

В одном из самых популярных компонентов ever является news.list. С давних времен разработчики используют его для вывода всего чего угодно. И в этом важном компоненте нарушается одна из главных заповедей производительности веб-приложений - там запросы в цикле :evil:.

Приведу пример.
/bitrix/components/bitrix/news.list/component.php:240
if(array_key_exists("PREVIEW_PICTURE", $arItem))
                $arItem["PREVIEW_PICTURE"] = CFile::GetFileArray($arItem["PREVIEW_PICTURE"] ); 
Независимо от настроек всегда получается картинка. И это в цикле:o! Строчкой позже делается аналогичный запрос для детальной картинки. Если у вас в news.list 100 элементов, ждите примерно 100 дополнительных запросов (а то и все 200:!:, если у вас есть и детальная картинка и анонсная).

Кажется, что решение проблемы состоит из 1 действия - выполнить запрос всех картинок разом. Но не тут то было. Метод CFile::GetFileArray не принимает массивы ID, только 1 файл за раз. И это, кстати, большая проблема многих методов Битрикс.

Рейтинг: 0  
Куклин Евгений 12.09.2013 09:26:14
Что мешает переделать на CFile::GetList()?
Рейтинг: 9.0652  
Долганин Антон 12.09.2013 11:24:27
Если у вас в news.list 100 элементов, ждите примерно 100 дополнительных запросов (а то и все 200:!:, если у вас есть и детальная картинка и анонсная).
Не зная технологии, не надо грешить, пожалуйста.

GetFileArray дергает достает один файл, действительно. Но вот запрос дергает несколько файлов из базы, в так называемый пакет (долго объяснять, коль вы код любите копать - покопаете).

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

Метод CFile::GetFileArray не принимает массивы ID
Плохо вы знаете API. Ловите пример:

 public static function GetFiles($miscID) {
   if (empty($miscID)) {
      return $miscID;
   }
   if (!is_array($miscID)) {
      $miscID = array($miscID);
   }
   $arFiles = array_unique($miscID);
   $uploadDir = COption::GetOptionString('main', 'upload_dir', 'upload');
   $rsFiles = CFile::GetList(array(), array('@ID' => implode(',', $arFiles)));
   $arFiles = array();
   while ($arFile = $rsFiles->Fetch()) {
      $arFile['SRC'] = '/' . $uploadDir . '/' . $arFile['SUBDIR'] . '/' . $arFile['FILE_NAME'];
      $arFiles[$arFile['ID']] = $arFile;
   }
   return $arFiles;
}


Передаете массив ID файлов, на выходе получаете массив файлов-массивов. Думаю, вы понимаете, почему тут нельзя заставить работать и в облаке - мы не знаем на каком сервере какой файл может лежать.
Рейтинг: 7.1743  
Долганин Антон 12.09.2013 11:25:49
А, да, еще, у CFile есть внутренний кеш. То есть даже если кеш компонента очищается, файлы лежат в кеше. По умолчанию на час. Волшебной контсантной вы можете увеличить это время.
Рейтинг: 0.5459  
Ерофеев Анатолий 12.09.2013 13:33:53
 Что мешает переделать на CFile::GetList()?
Это больше вопрос к разработчикам Битрикса. Действительно, что им мешает использовать их метод в их компоненте?

Про пакеты и кеширование файлов я знаю, но кеширование это считаю полумерой, потому что получаются файлы подряд. Живой пример - у меня в списке из 70 элементов картинки получились из БД за 40 запросов. Уменьшение есть, потому что некоторые файлы таки находились в таблице b_file рядом, но далеко не все.
Надеюсь, с тем что 1 запрос лучше чем 40 и 70 вы спорить не будете.
За пример спасибо, но что-то подобное я уже разработал в своем проекте. Идея у нас одинаковая (ее же предложил и Евгений Куклин) - использовать GetList.

И прошу обратить внимание на формулировку идеи:
я предлагаю этот метод написать и использовать в news.list, стандартном компоненте битрикса. Можно сколько угодно говорить, что это просто и достаточно использовать GetList и т.д. и т.п. - но содержимое стандартного компонента от этого не изменится =)
Рейтинг: 0  
Долганин Антон 13.09.2013 15:21:43
Анатолий, как вы предлагаете поступать при облаке?