2009-07-15 3 views
0

Angesichts jeder Abfrage (Gruppierung, Joins und Unterabfragen sind alle in beliebiger Kombination möglich), möchte ich es mit Paginierung so effizient wie möglich zu brechen. Im Moment führe ich einfach die Abfrage aus, zähle dann die Anzahl der an PHP zurückgegebenen Zeilen, finde heraus, wie viele Seiten der Daten vorhanden sind, zeige die auf der aktuellen Seite an und gebe die richtigen Links zu den anderen Seiten aus.programmatisch ersetzen SELECT-Felder in SQL-Abfrage zur Ermittlung der Anzahl der Ergebnisse

Scheint mir, dass das potenziell sehr große Ergebnis, das von der Abfrage gesetzt wird, jedoch meistens verschwendet wird. Gibt es eine Möglichkeit, die Abfrage zweimal auszuführen, wenn Sie COUNT (*) zum ersten Mal auswählen, um eine einzelne Zahl mit den zu paginierenden Zeilen zu erhalten, und zum zweiten Mal die ursprüngliche Abfrage mit den richtigen Limits basierend auf der aktuell angezeigten Seite ausführen? Würde dies den Datenbankserver deutlich weniger besteuern?

Für eine triviale Abfrage ist das kein Problem ... ersetzen Sie alles nach SELECT und vor WHERE mit count (*). Dies funktioniert jedoch nicht, wenn eine Gruppierung in der Abfrage vorhanden ist, da Sie die Anzahl in jeder Gruppe und nicht die Gesamtzahl der Zeilen erhalten. Wenn Sie die Spalten a, b und c gruppieren, ist es richtig, count (distinct a, b, c) auszuwählen? Muss für die Bearbeitung von Unterabfragen etwas Besonderes getan werden?

Antwort

3

Sie könnten wahrscheinlich nächste verwenden:

select count(*) 
from (<original select query>) 
+0

Ich mag die Einfachheit dieser Methode. Besteht die Gefahr einer schlechten Performance? Scheint sicher genug ... –

+0

endete damit aufgrund der möglichen Race-Bedingung von SQL_CALC_FOUND_ROWS mit mehreren gleichzeitigen Anfragen –

+0

Sicher gibt es das Risiko einer schlechten Leistung - diese Abfrage kann nicht viel schneller als die ursprüngliche sein, vor allem, wenn es einige haben Typenklauseln (Überprüfung von Aggregatwerten usw.). Nun, in SQL Land gibt es immer das Risiko einer schlechten Leistung :) – Arvo

2

Dies kann helfen: mysql hat Limit Funktion:

select * 
from mytable 
limit 10,40 

Wo Limit 10,40 Mittel mich 40 Ergebnisse mit 10 Ergebnisse, beginnend geben (die 0 basiert).

Mit dieser Funktion können Sie Seitenumbrüche erstellen. Im obigen Beispiel bedeutet 40 40 Ergebnisse/Seite.

+0

Ich verstehe, dass Sie jedoch irgendwie die Gesamtzahl der übereinstimmenden Datensätze erhalten müssen, um richtige Seitenumbruch zu erstellen. –

+0

Richtig, dieser Teil ist nicht in meiner Antwort enthalten. Es ist nur ein Anfangspunkt. –

4

können Sie SQL_CALC_FOUND_ROWS verwenden Sie Ihr kleines Ergebnismenge zu geben, sondern auch die Größe der unbegrenzten Ergebnismenge haben MySQL berechnen:

SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name LIMIT 10; 

SELECT FOUND_ROWS(); 
+0

hat noch nie von SQL_CALC_FOUND_ROWS gehört. Ich bin nicht sicher, ob ich es aufgrund der Methoden, die wir verwenden müssen, um die Datenbank abzufragen, verwenden kann, aber es funktioniert gut in der Befehlszeile. ein anderes Werkzeug ist immer eine gute Sache! –

2

Sie können mySQL stellen die Anzahl der Zeilen zu berechnen, die gewesen wäre ohne die Limit-Klausel zurückgegeben, indem SQL_CALC_FOUND_ROWS verwendet.

Dies wird Ihnen die erste Seite von 20:

Dann können Sie für die Anzahl der Zeilen stellen, die Rückkehr ohne SQL_CALC_FOUND_ROWS gewesen wäre:

SELECT FOUND_ROWS() AS numrows 

Dies beantwortet werden aus dem Treiber ohne eine weitere Anfrage an den Datenbankserver. Es sollte auch mit komplexeren Abfragen funktionieren.

0

ich ein bisschen in der Entwicklungsumgebung experimentieren würde, um zu sehen, ob es ein Performance-Vorteil ist.

Sie können das Ergebnis basierend auf Sätzen pro Seite begrenzen, indem Sie die LIMIT-Klausel verwenden, wie MercerTrieste vorschlägt. Allerdings machen Sie jetzt pro Seite eine Reise zur Datenbank, was normalerweise zu vermeiden ist. Ich gehe davon aus, dass Ihr PHP-Skript einen Cursor verwendet, um Daten vom MySQL-Server abzurufen, und ich stelle mir vor, dass der Cursor geöffnet bleibt, um diese Daten für Ihre anderen Seiten abzurufen. Wenn Sie LIMIT-Abfragen ausführen, können Sie den Datenbankserver möglicherweise mehr besteuern.Natürlich würde ich testen/experimentieren, um das herauszufinden, indem ich die Datenbankbelastung mit einem MySQL-Performance-Monitor-Tool überwache, falls es eines gibt.

Sie müssen wahrscheinlich nicht einmal einen COUNT (*) erstellen, um die Seiten zu paginieren. Sie müssen nur bestimmen, wie viele Datensätze Sie pro Seite haben möchten.

D.h. tun (psuedocode folgt)

SELECT <columns> FROM <table> LIMIT <records-per-page>; 
while (More data available for future pages) 
{ 
    records-shown += records-per-page; 
    SELECT <columns> FROM <table> LIMIT <records-per-page>,<records-shown>; 
} 

Zugegeben, andere Wege, es sind wahrscheinlich sauberer machen.