2010-05-08 7 views
3

J'essaie de faire paginer Cakephp tirer parti de la fonction SQL_CALC_FOUND_ROWS dans mysql pour retourner le nombre total de lignes tout en utilisant LIMIT. Heureusement, cela peut éliminer la double requête de paginateCount(), puis paginate().cakephp paginate using mysql SQL_CALC_FOUND_ROWS

Je l'ai mis dans mon app_model.php, et il fonctionne essentiellement, mais il pourrait être mieux fait. Quelqu'un peut-il m'aider à comprendre comment remplacer paginate/paginateCount afin qu'il n'exécute que 1 SQL stmt?

/** 
* Overridden paginateCount method, to using SQL_CALC_FOUND_ROWS 
*/ 
public function paginateCount($conditions = null, $recursive = 0, $extra = array()) { 
    $options = array_merge(compact('conditions', 'recursive'), $extra); 
    $options['fields'] = "SQL_CALC_FOUND_ROWS `{$this->alias}`.*"; 

Q: comment obtenez-vous la valeur limite utilisée dans SAME paginate()? Q: pouvons-nous en quelque sorte obtenir les résultats de la requête à paginer directement, sans la requête supplémentaire?

$cache_results_from_paginateCount = $this->find('all', $options); 
    /* 
    * note: we must run the query to get the count, but it will be cached for multiple paginates, so add comment to query 
    */ 
    $found_rows = $this->query("/* do not cache for {$this->alias} */ SELECT FOUND_ROWS();"); 
    $count = array_shift($found_rows[0][0]); 
    return $count; 
} 

/** 
* Overridden paginate method 
*/ 
public function paginate($conditions, $fields, $order, $limit, $page = 1, $recursive = null, $extra = array()) { 
    $options = array_merge(compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive'), $extra); 

Q: peut-on obtenir en quelque sorte $ cache_results_for_paginate directement à partir paginateCount()?

return $cache_results_from_paginateCount; // paginate in only 1 SQL stmt 
    return $this->find('all', $options); // ideally, we could skip this call entirely 
} 
+0

Je veux simplement ajouter ici que SQL_CALC_FOUND_ROWS est souvent beaucoup, beaucoup plus lent que d'utiliser un droit COUNT(), et 2 requêtes. La raison en est que Mysql cherche les données. Surtout les grands ensembles de données, les solutions SQL_CALC_FOUND_ROWS peuvent prendre littéralement des millions de fois plus longtemps (100+ secondes contre 0,004 secondes sur un million d'enregistrements). – Oddman

Répondre

0

La façon dont je résous ceci pour paginer les résultats d'un service Web qui renvoie les résultats de la page en cours et le nombre total de résultats disponibles dans la même réponse est de copier la propriété paginate du contrôleur au modèle dans l'action de votre contrôleur, avant d'appeler $ this-> paginate(); pour que mes paramètres de pagination soient disponibles dans la méthode paginateCount() du modèle. Ensuite, dans paginateCount(), lancez l'appel au webservice pour obtenir les résultats. Puis stocker les résultats dans une propriété du modèle puis renvoyer le nombre total de résultats disponibles. Ensuite, dans la méthode paginate() du modèle, je retourne les résultats que j'ai récupérés et stockés dans la méthode paginateCount().

Peut-être que quelque chose dans ce sens pourrait fonctionner pour vous aussi?

+0

J'ai utilisé une classe var statique pour mettre en cache le paginateResponse, mais il ne m'est jamais arrivé que je puisse aussi passer les options paginate par le même mécanisme. Cela semble fonctionner correctement tant que je peux définir récursif = -1, mais s'il y a une association dans la pagination, alors le "SELECT FOUND ROWS" est appelé APRES les requêtes d'association, et retourne les mauvais résultats. – michael

+0

également avoir du mal à obtenir la valeur $ fields correcte dans find(). en cours d'utilisation $ fields = is_array ($ fields) ? array_unshift ($ fields, 'SQL_CALC_FOUND_ROWS') :! vide ($ champs)? array ('SQL_CALC_FOUND_ROWS', champs $) : "SQL_CALC_FOUND_ROWS' {$ this-> alias}. * "; mais vraiment seulement testé pour $ fields = ;; – michael

Questions connexes