Как правильно выгружать большие объемы данных
Часто встает задача импорта каких либо сущностей с портала посредством rest. При этом при большом количестве сущностей прямой подход к задаче, с установкой фильтра и передачей в каждый следующий запрос start = start+50
, не оптимальный.
Так как, при использование start >= 0
на каждый запрос выполняется еще и запрос подсчета количества элементов удовлетворяющих фильтру. Что при большом количестве элементов, попадающих в него, или при сложной фильтрации работает медленно.
Поэтому в случае если вам не нужно количество элементов ( например вам нужно просто 10 последних записей ) или вы делаете импорт всех записей по фильтру, передавайте start = -1
.
Данный параметр отключит выполнение запроса подсчета количества элементов и сильно ускорит выборку.
Для выполнения импорта, при этом необходимо будет отсортировать записи по ID и добавить в фильтр условие ID > значения последнего элемента. И с каждым шагом увеличивать его значение. Значение же последнего элемента брать из последнего значения полученного результата.
Условием остановки импорта будет пустой ответ, или то, что в ответе элементов меньше 50.
Ниже приведен пример кода и сравнение времени выполнения с классическим подходом. Так при 2 387 743 лидах, с одинаковыми правами и фильтром, время выполнения уменьшилось с 49.9 секунд до 0,097 секунд.
Пример
$tokenID = 'XXXXXXXXXXXXXXXXXXXXX'; $host = 'XXXX.bitrix24.ru'; $user = 1; /** * Начинаем с нуля или с какого то предыдущего шага */ $leadID = 0; $finish = false; while (!$finish) { /** * Выполняем пока не заберем все данные, в этом случае не стоит забывать и про задержку между хитами. * Либо каждый раз выбираем только 50, начиная с того элемента, на котором остановилась прошлая итерация */ $http = new \Bitrix\Main\Web\HttpClient(); $http->setTimeout(5); $http->setStreamTimeout(50); $json = $http->post( 'https://'.$host.'/rest/'.$user.'/'.$tokenID.'/crm.lead.list/', [ 'order' => ['ID' => 'ASC'], 'filter' => ['>ID' => $leadID], 'select' => ['ID', 'TITLE', 'DATE_CREATE'], 'start' => -1 ] ); $result = \Bitrix\Main\Web\Json::decode($json); if (count($result['result']) > 0) { foreach ($result['result'] as $lead) { $leadID = $lead['ID']; } // Do something } else { $finish = true; } } /* //Результаты выполнения rest запроса с использованием count. Array ( [result] => Array ( [0] => Array() [1] => Array() ..... [49] => Array() ) [next] => 50 [total] => 2387743 [time] => Array ( [start] => 1581607213.4833 [finish] => 1581607263.3997 [duration] => 49.916450023651 [processing] => 49.899916887283 [date_start] => 2020-02-13T18:20:13+03:00 [date_finish] => 2020-02-13T18:21:03+03:00 ) ) //Результаты выполнения rest запроса без использования count. Array ( [result] => Array ( [0] => Array() [1] => Array() ..... [1] => Array() ) [total] => 0 [time] => Array ( [start] => 1581609136.3857 [finish] => 1581609136.4835 [duration] => 0.097883939743042 [processing] => 0.068500995635986 [date_start] => 2020-02-13T18:52:16+03:00 [date_finish] => 2020-02-13T18:52:16+03:00 ) ) */