Могу ли я остановить CakePHP выборку всех строк для запроса?

Я использую CakePHP с вызовами $ modelName-> find (…), чтобы выбрать довольно много строк (может быть сотни)

Как правило, в PHP / MySQL, конечно, это не проблема, поскольку вы извлекаете их в цикл while. Но CakePHP загружает все строки в массив, который исчерпывает лимит памяти.

Есть ли способ использовать конструкторы $ modelName-> find (…), но возвращать итератор для извлечения каждой строки по требованию?

Спасибо, Дэвид

Нет, из коробки Cake PHP (и ActiveRecord в целом) не поддерживает итерацию по набору результатов, подобному этому. Если у вас есть прецедент, где вам действительно нужны все записи таблицы, вам, вероятно, лучше использовать необработанный SQL. (или переосмысление вашего варианта использования).

Вы также можете (и, вероятно, уже подумали) использовать какое-либо смещение, а call -> найти несколько раз. Если вы примете такой подход, не забудьте заказать свой результат, заданный в каком-либо поле, чтобы обеспечить детерминированный результат. Кажется, что базы данных возвращают отсортированные строки, когда вы покидаете ORDER BY. Я лично не пробовал это, и это кажется неэффективным с точки зрения нескольких запросов, но это то, что стоит попробовать.

Если ваша проблема вызвана отношениями вашей модели, вы можете уменьшить рекурсию следующим образом:

$ modelname-> recursive = -1;

то вы получите только данные текущей модели, без каких-либо отношений.

Итерации по всем записям, вы сможете получить один за другим их отношения, запрашивающие снова с рекурсивными> 0

Вот код, который вы можете использовать для обработки таблицы несколькими строками за раз

  $limit = 10; $loop_no = 0; do { $handles = $this->SocialChannelHandle->find('all', array( 'fields' => array('brand_id', 'handle'), 'conditions' => array('social_channel_id' => $facebook['SocialChannel']['id']), 'limit' => $limit, 'offset' => $limit * $loop_no, 'order' => 'id asc', 'recursive' => -1) ); $loop_no++; } while (count($handles) == $limit); 

Если вы используете хранимую процедуру для создания запроса, может быть хорошей идеей имитировать поведение подкачки, чтобы получать сегменты запроса за раз. В этом случае вы отправите два дополнительных параметра в хранимую процедуру для индекса начальной строки и «page» -size и верните настройку оператора select, чтобы извлекать только те записи между row_index + 1 и row_index + page_size.

Все это может быть добавлено в дополнительный слой цикла, поэтому вы получаете новый сегмент, а затем внутри этого просматриваете каждую строку в этом сегменте.

Я понимаю, что вы ищете итератор, возвращаемый из условия поиска, но как насчет использования предложения LIMIT с переменным смещением (например, число строк, которое вы хотите вернуть сразу)? Это может вызвать некоторые проблемы с параллелизмом, но если вы также включаете предложение ORDER BY id, вы должны увидеть последовательное поведение в возвращаемых строках. Затем, в вашем цикле, просто повторно выдавайте запрос find (…).

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

Наконец, если вы действительно ищете производительность, я думаю, что CakePHP может не быть вашей сумкой чая. Это улучшает скорость с новыми выпусками, но я считаю, что он все еще значительно отстает от других фреймворков, когда дело доходит до производительности.

Я думаю, это невозможно, потому что CakePHP динамически создает многомерный массив, представляющий ваши отношения с сущностью базы данных. Это должно быть сделано после извлечения всех строк запроса, чтобы CakePHP мог знать все возможные связанные объекты.

Пример:

Для построения соответствующего многомерного массива необходимо выбрать 3 строки:

 Статья 1
   |
   - Комментарий 1
   |
   - Комментарий 2
   |
   - Комментарий 3

Результат запроса (1..n):

 Статья |  Комментарий
 -----------------
 1 |  1
 -----------------
 1 |  2
 -----------------
 1 |  3

Вы также можете получать так много данных из-за своих отношений модели. Для вашего вызова someModel-> find (), сколько других моделей связано с некоторыми моделями?

Я использовал по крайней мере 1000 строк в массиве на типичном сервере общедоступного хостинга без проблем с памятью.

UPDATE: вы можете просто использовать поведение Containable, если вы не хотите, чтобы связанные модели были возвращены. Итак, если вы пытаетесь найти все сообщения, но не хотите комментариев, вы можете использовать синтаксис $ this-> Post-> contains (), чтобы возвращать только записи Post. Containable – это поведение, которое должно быть добавлено в вашу модель с помощью параметра $ actAs, $ actAs = array ('Containable');

вы можете добавить ограничение на запрос на поиск. У меня нет времени, чтобы написать полный ответ. Я обнов его позже.

И нет, из того, что я знаю, когда вы выполняете запрос в mysql или с обычным драйвером. В любом случае он вернет все элементы вашего выбора. Поэтому, если у вас проблема с ограничением памяти, это может быть где-то еще. Вы можете добавить ограничение на определенное количество строк. Если ваша таблица имеет множественную зависимость, но вам не нужно загружать каждый внешний ключ, вы можете использовать атрибут «contains», чтобы загружать только то, что вам нужно.

Не могли бы вы дать нам описание вашей таблицы. и что вы хотите выбрать.

Вы можете либо ограничить вызов метода поиска с помощью рекурсивного параметра ( API для поиска Model # find ), либо вы можете развязать ассоциации моделей «на лету» и уменьшить количество полученных данных ( создание и уничтожение ассоциаций на лету )

Ruby On rails обрабатывает это намного лучше. Поведение по умолчанию не должно включать никаких других таблиц, если вы не используете: include =>: table_name, а затем он будет генерировать соединения на лету.

Нет причин, по которым он не может этого сделать, просто нет.