Активная запись CodeIgniter: загрузка одной строки за раз

Метод normal result() описанный в документации, сразу же загружает все записи. Мое приложение должно загружать около 30 000 строк и по одному, отправляя их в сторонний API индекса поиска. Очевидно, что загрузка всего в память сразу не работает (ошибки из-за слишком большой памяти).

Итак, мой вопрос: как я могу добиться эффекта обычного метода API MySQLi, в котором вы загружаете одну строку за раз в цикле?

Вот что вы можете сделать.

 while ($row = $result->_fetch_object()) { $data = array( 'id' => $row->id 'some_value' => $row->some_field_name ); // send row data to whatever api $this->send_data_to_api($data); } 

В это время будет получена одна строка. Проверьте исходный код CodeIgniter, и вы увидите, что они будут делать это при выполнении метода result ().

Для тех, кто хочет сохранить память на большом результирующем наборе:

Начиная с CodeIgniter 3.0.0 , существует функция unbuffered_row ,

Все вышеприведенные методы загружают весь результат в память (предварительная выборка). Используйте unbuffered_row () для обработки больших наборов результатов.

Этот метод возвращает одну строку результата без предварительной выборки всего результата в памяти, как это делает row (). Если ваш запрос имеет более одной строки, он возвращает текущую строку и перемещает указатель внутренних данных вперед.

 $query = $this->db->query("YOUR QUERY"); while ($row = $query->unbuffered_row()) { echo $row->title; echo $row->name; echo $row->body; } 

Вы можете опционально передать «объект» (по умолчанию) или «массив», чтобы указать тип возвращаемого значения:

 $query->unbuffered_row(); // object $query->unbuffered_row('object'); // object $query->unbuffered_row('array'); // associative array 

Официальный документ: https://www.codeigniter.com/userguide3/database/results.html#id2

Ну, есть метод row () , который возвращает только одну строку в качестве объекта или метод row_array () , который делает то же самое, но возвращает массив (конечно).

Таким образом, вы можете сделать что-то вроде

 $sql = "SELECT * FROM yourtable"; $resultSet = $this->db->query($sql); $total = $resultSet->num_rows(); for($i=0;$i<$total;$i++) { $row = $resultSet->row_array($i); } 

Это выбирает в цикле каждую строку из всего набора результатов.
Это примерно так же, как выборка и цикл по методу $this->db->query($sql)->result() который я считаю.

Если вам нужна строка за раз, либо вы делаете 30 000 вызовов, либо вы выбираете все результаты и выбираете их по одному, либо вы получаете все и ходите по массиву. Теперь я не вижу никакого выхода.

Ну, дело в том, что result() отдает весь ответ запроса. row() просто извлекает первый случай и выгружает остальное. Однако запрос может по-прежнему отображать 30 000 строк в зависимости от используемой вами функции.

Один дизайн, который подойдет вашему делу, будет:

 $offset = (int)@$_GET['offset']; $query = $this-db->query("SELECT * FROM table LIMIT ?, 1", array($offset)); $row = $query->row(); if ($row) { /* Run api with values */ redirect(current_url().'?offset'.($offset + 1)); } 

Это займет одну строку, отправьте ее в api, обновите страницу и используйте следующую строку. Это приведет к тому, что страница не будет иметь тайм-аут. Однако, скорее всего, потребуется некоторое время с 30 000 записей и обновлениями, поэтому вы можете настроить свой LIMIT ?, 1 на большее число, чем 1 и перейти к result() и foreach() нескольким причинам за одну страницу.