Могу ли я остановить CakePHP, извлекающий все строки для запроса? - PullRequest
2 голосов
/ 12 февраля 2009

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

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

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

Спасибо, David

Ответы [ 11 ]

4 голосов
/ 03 ноября 2009

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

$ modelname-> recursive = -1;

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

Перебирая все записи, вы сможете поочередно получать их отношения, запрашивая снова с рекурсивом> 0

3 голосов
/ 09 декабря 2012

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

    $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);
2 голосов
/ 12 февраля 2009

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

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

0 голосов
/ 24 апреля 2018

Прошло много времени, но так как этот вопрос возник в поиске, я подумал упомянуть, что на самом деле есть встроенный способ сделать это. Что-то вроде:

$page = 1;
$limit = 100;
while ($posts = $this->Post->find('all', array(
   'conditions' => ...,
   'page' => $page,
   'limit' => $limit,
   ...
))) {
    foreach ($posts as $post) {
        ...deal with one row...
    }
    $page++;
}

будет разбивать на страницы набора данных, хотя и с некоторым снижением производительности, поскольку запрос повторяется при каждом цикле while.

(не проверено)

0 голосов
/ 18 апреля 2011

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

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

0 голосов
/ 04 ноября 2009

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

0 голосов
/ 16 февраля 2009

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

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

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

0 голосов
/ 12 февраля 2009

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

Пример:

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

Article 1
  |
  -- Comment 1
  |
  -- Comment 2
  |
  -- Comment 3

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

Article | Comment
-----------------
1       | 1
-----------------
1       | 2
-----------------
1       | 3
0 голосов
/ 12 февраля 2009

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

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

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

0 голосов
/ 12 февраля 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...