Метод 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()
нескольким причинам за одну страницу.