2009-02-11 10 views
2

J'utilise CakePHP avec modelName- $> trouver (...) appelle à sélectionner un certain nombre de lignes (peut-être des centaines)Puis-je empêcher CakePHP de récupérer toutes les lignes d'une requête?

Normalement, en PHP/MySQL Bien sûr, ce ne serait pas une problème, comme vous les récupérez dans une boucle while. Mais, CakePHP charge toutes les lignes dans un tableau qui épuise la limite de mémoire .

Existe-t-il un moyen d'utiliser les constructions $ modelName-> find (...) mais de renvoyer un itérateur pour extraire chaque ligne à la demande?

Merci, David

Répondre

2

Non, out of the box Cake PHP (et ActiveRecord en général) ne supporte pas l'itération sur un ensemble de résultats comme ça. Si vous avez un cas d'utilisation où vous avez besoin de les enregistrements d'une table, il est probablement préférable d'utiliser du SQL brut. (ou repenser votre cas d'utilisation).

Vous pouvez également (et vous avez probablement déjà pensé à) utiliser un décalage quelconque, et appeler -> trouver plusieurs fois. Si vous adoptez cette approche, n'oubliez pas de classer votre résultat dans un champ afin d'obtenir un résultat déterministe. Les bases de données ne semblent renvoyer les lignes triées que lorsque vous laissez un ORDER BY désactivé. Je n'ai pas personnellement essayé cela, et il semble inefficace du point de vue des requêtes multiples, mais c'est quelque chose qui vaut la peine d'être essayé.

+0

En fait, je suis en train de mettre en œuvre ce genre de choses en utilisant PDO et les requêtes tamponnées. Je retourne un objet de ma fonction de recherche qui implémente iterable, et possède un handle pour l'instruction. http://stackoverflow.com/questions/531536/php-orm-query-results-arrays-vs-result-handle-wrapped-in-iterator-interface – SchizoDuckie

+0

et les gens disent que le gâteau est lent ... huph! – Xeoncross

+0

Utilisez la pagination intégrée! '$ this-> Model-> paginate()' –

0

Si vous utilisez une procédure stockée pour produire la requête, il pourrait être une bonne idée d'imiter le comportement de recherche de personnes pour obtenir des segments de la requête à la fois. Dans ce cas, vous devez envoyer deux paramètres supplémentaires à la procédure stockée pour l'index de ligne de début et la taille "page", et revenir ajuster l'instruction select pour récupérer uniquement les enregistrements entre row_index + 1 et row_index + page_size.

Tout cela peut être placé dans une couche supplémentaire de bouclage, de sorte que vous obtenez un nouveau segment, puis à l'intérieur de chaque ligne de ce segment.

+0

Merci, C'est une solution que je suppose. Le seul problème est qu'il y a un compromis entre la mémoire et les requêtes. Donc, si j'ai 1000 requêtes et j'ai de la mémoire pour 100, alors je dois faire 10 requêtes. Mais je dois encore stocker 100 lignes à la fois. Devient pire à 10 000 ou 100 000 ... Dommage vraiment. Dave – daviddoran

+0

Cela dépend de ce que vous faites avec les données de l'autre côté. Si vous l'affichez, vous pouvez utiliser AJAX pour continuer à remplir en fonction de chaque nouveau segment, ce qui vous fera gagner du temps lors du chargement initial de la page. Le fléau du programmeur, vous devez échanger du temps pour l'espace et vice-versa. – notnot

+0

Je cours à travers toutes les lignes (ce sont des métadonnées pour les lignes des autres tables ... qui sont des enfants d'autres lignes ..) et fait des stats pour générer un tableau de résumé. J'ai juste besoin de "voir" chaque rangée une fois ce qui devrait être bien, même si ça prend un peu mais le chargement est un problème. Offset c'est ce qu'il semble. – daviddoran

0

Vous pourriez également obtenir autant de données en raison de vos relations de modèle. Pour votre appel someModel-> find(), combien d'autres modèles sont liés à someModel?

J'ai utilisé au moins 1000 lignes dans un tableau sur un serveur d'hébergement partagé typique sans problèmes de mémoire. MISE À JOUR: Vous pouvez simplement utiliser le comportement Contenable si vous ne souhaitez pas que les modèles associés soient renvoyés. Donc, si vous essayez de trouver tous les messages mais que vous ne voulez pas les commentaires, vous pouvez utiliser la syntaxe $ this-> Post-> contain() pour ne renvoyer que les enregistrements Post. Le Containable est un comportement qui doit être ajouté dans votre modèle en utilisant le paramètre $ actAs, $ actAs = array ('Containable');

0

Je comprends que vous êtes à la recherche d'un itérateur retourné à partir de la condition de recherche, mais que pensez-vous de l'utilisation de la clause LIMIT avec un décalage variable (par exemple le nombre de lignes que vous voulez)? Cela pourrait faire apparaître des problèmes de concurrence, mais si vous incluez également la clause id ORDER BY, vous devriez voir un comportement cohérent dans les lignes retournées. Ensuite, dans votre boucle, lancez simplement la requête find (...) à plusieurs reprises. Ceci n'est clairement pas une solution élégante comme le ferait un itérateur, mais j'imagine que le fait de répéter plusieurs fois une requête pour retourner plus de lignes équivaudrait à compenser les économies en récupérant plusieurs lignes à la fois. (dans le gâteau). Enfin, si vous recherchez vraiment la performance, alors je pense que CakePHP n'est peut-être pas votre sac de thé. Il s'améliore en vitesse avec les nouvelles versions, mais je crois qu'il est encore en retard par rapport aux autres frameworks en termes de performances.

+0

Je suppose que l'utilisation de décalage et de limite est la meilleure façon. J'espérais ne pas avoir à y recourir, en supposant qu'il y aurait un moyen d'accéder manuellement à la méthode de récupération de CalePHP. C'est juste dommage parce que ce que je fais devrait être assez efficace mais il y a tellement de frais généraux. Arg ... Dave – daviddoran

+0

Overhead est le nom du jeu avec Cake! –

0

Je suppose que cela n'est pas possible car CakePHP construit dynamiquement un tableau multidimensionnel représentant vos relations d'entité de base de données. Cela devrait être fait après avoir récupéré toutes les lignes de requête afin que CakePHP connaisse toutes les entités liées possibles.

Exemple:

trois lignes doit être récupérée afin de construire le tableau multidimensionnel correspondant:

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

résultat de la requête (1..n):

 
Article | Comment 
----------------- 
1  | 1 
----------------- 
1  | 2 
----------------- 
1  | 3 
+0

Je ne suis pas certain de comprendre. Habituellement, même avec une hiérarchie complexe, vous pouvez utiliser un nombre constant de requêtes. Surtout dans CakePHP la façon dont il charge dans la mémoire. Donc, si vous avez deux articles, chacun avec cinquante commentaires, vous pouvez d'abord obtenir les articles, puis SELECT * commentaires WHERE article_id IN (article_ids) – daviddoran

+0

Ceci est inefficace et une mauvaise pratique. CakePHP utilise * chargement avide * qui empêche le redouté problème 1 + N dans lequel aller chercher 100 messages que chacun doit afficher leurs déclencheurs d'auteur 101 requêtes de base de données. Grâce à l'utilisation de chargement passionné, les 101 requêtes peuvent être réduites à 2. – knoopx

0

Vous pouvez ajouter une limite à votre demande de recherche. Je n'ai pas le temps maintenant d'écrire une réponse complète. Je vais le mettre à jour plus tard.

Et non, d'après ce que je sais, quand vous faites une requête dans mysql ou avec le driver normal. Il retournera tous les éléments de votre sélection de toute façon. Donc, si vous avez un problème avec la mémoire limite, il se peut que ce soit ailleurs. Vous pouvez ajouter une limite à un certain nombre de lignes. Si votre table a plusieurs dépendances mais que vous n'avez pas besoin de charger chaque clé étrangère, vous pouvez utiliser l'attribut "contains" pour charger uniquement ce dont vous avez besoin.

Pourriez-vous nous décrire votre table? et ce que vous voulez sélectionner.

4

Si votre problème est causé par les relations de votre modèle, vous pouvez réduire la récursion cette façon:

modelname- $> récursive = -1;

alors vous obtiendrez seulement les données du modèle actuel, sans aucune relation.

Itération à travers tous les enregistrements, vous serez en mesure d'obtenir un par un leurs relations d'interrogation à nouveau avec récursif> 0

0

Ruby Sur les rails, cette fonction est meilleure. Le comportement par défaut est de ne pas inclure d'autres tables à moins que vous n'utilisiez: include =>: nom_table, puis il générera des jointures à la volée.

Il n'y a aucune raison de ne pas pouvoir faire cela, il ne le fait pas .

2

Voici le code que vous pouvez utiliser pour traiter une table quelques lignes à la fois

$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); 
Questions connexes