2010-11-12 2 views
9

Ich wurde von einem Kollegen gesagt, dass das Ausführen einer SQL-Anweisung die Daten immer vom Datenbankserver in den RAM/Swap versetzt. Daher ist es nicht praktisch, große Ergebnismengen auszuwählen.Wird beim Ausführen einer Anweisung immer Speicher für die Ergebnismenge benötigt?

dachte ich, dass ein solcher Code

my $sth = $dbh->prepare('SELECT million_rows FROM table'); 
while (my @data = $sth->fetchrow) { 
    # process the row 
} 

die Ergebnismenge zeilen abruft, ohne sie RAM geladen zu werden. Aber ich kann keinen Hinweis darauf in DBI oder MySQL-Dokumenten finden. Wie wird das Ergebnis wirklich erstellt und abgerufen? Funktioniert es für einfache Selects und Joins?

+0

Frage nach dem Zweck, warum müssen Sie Millionen Zeilen von Datensatz abrufen und alle abrufen? "mysqldump" sollte passender sein – ajreal

+0

@ajreal: Ich muss alle Zeilen in der Reihenfolge der Einfügung verarbeiten und einige Berichte generieren. – planetp

+0

ok, ist es vernünftig das zu tun? Mysql-Funktion verwenden, um Ansicht zu generieren, temporäre Tabelle nicht ausreichend für Bericht? oder erwägen Sie sogar, die BIG-Ergebnisse in eine Datei zu dumpen und öffnen Sie die Datei für die Verarbeitung – ajreal

Antwort

6

Ihr Kollege hat Recht.

Standardmäßig verwendet das Perl-Modul DBD :: mysql mysql_store_result, das tatsächlich alle SELECT-Daten einliest und im RAM zwischenspeichert. Wenn Sie diesen Standard nicht ändern, wenn Sie Zeile für Zeile in DBI abrufen, werden sie nur aus dem Speicher gelesen.

Dies ist normalerweise, was Sie wollen, es sei denn, Sie haben sehr sehr große Ergebnismengen. Andernfalls, bis Sie die letzten Daten von mysqld zurückbekommen, muss es diese Daten bereithalten und mein Verständnis ist, dass es Blöcke beim Schreiben in die gleichen Zeilen (Blöcke? Tabellen?) Verursacht.

Denken Sie daran, moderne Maschinen haben viel RAM. Ein Ergebnissatz mit Millionen Zeilen ist normalerweise keine große Sache. Selbst wenn jede Zeile bei 1 KB ziemlich groß ist, sind das nur 1 GB RAM plus Overhead.

Wenn Sie Millionen von Zeilen von BLOBs verarbeiten möchten, möchten Sie vielleicht mysql_use_result - oder Sie möchten diese Zeilen in Blöcken mit fortschreitender Verwendung von LIMIT x,y auswählen. Weitere Informationen finden Sie unter mysql_use_result und mysql_store_result in perldoc DBD::mysql.

+0

+1, wusste nicht, dass DBD :: mysql das tut. Allerdings ist Ihr Kommentar, dass Sie nicht kümmern sollten, es sei denn, Sie sind in Gefahr, RAM zu leeren ist ein schlechter Rat - in der Regel sollten Sie nur die Daten erhalten, die Sie brauchen und wenn Sie keine Millionen Zeilen benötigen (und Sie selten tun), Du solltest sie nicht alle bekommen. Solch ein Ansatz wird die Skalierbarkeit irreparabel ruinieren (die Situation ist etwas besser, wenn die Bibliothek Caching auf Anwendungsebene und nicht auf Sitzungsebene durchführt, aber immer noch nicht gut - wenn dieser Cache oft invalidiert wird, holt man immer wieder 1GB Daten dorthin, wo man sie braucht viel weniger) – Unreason

1

Ich bin nicht sehr vertraut mit diesem, aber es sieht aus wie DBD :: mysql kann entweder alles im Voraus abrufen oder nur nach Bedarf, basierend auf dem Attribut mysql_use_result. Konsultieren Sie die Dokumentation zu DBD :: mysql und MySQL.

5

Dies ist nicht wahr (wenn wir über den Datenbankserver selbst sprechen, nicht über Client-Schichten).

MySQL kann die gesamte Ergebnismenge puffern, aber dies ist nicht unbedingt getan, und wenn getan, nicht unbedingt in RAM.

Die resultset gepuffert werden, wenn Sie Inline-Ansichten verwenden (SELECT FROM (SELECT …)), muss die Abfrage sortieren, um (die als using filesort gezeigt wird), oder der Plan erfordert eine temporäre Tabelle erstellen (die als using temporary im Abfrageplan angezeigt wird) .

Auch wenn using temporary, MySQL nur die Tabelle im Speicher hält, wenn ihre Größe nicht die in tmp_table festgelegte Grenze überschreitet. Wenn die Tabelle dieses Limit überschreitet, wird sie von memory in MyISAM konvertiert und auf der Festplatte gespeichert.

Sie können jedoch MySQL explizit anweisen, die Ergebnismenge zu puffern, indem Sie die SQL_BUFFER_RESULT Anweisung an die äußerste SELECT anhängen.

Siehe die docs für weitere Details.

3

Nein, so funktioniert es nicht.

Die Datenbank enthält keine Zeilen im RAM/Swap.

Allerdings wird es versuchen, und mysql versucht hier, so viel wie möglich zu cachen (Indizes, Ergebnisse, etc ...). Ihre mysql-Konfiguration gibt Werte für die verfügbaren Speicherpuffer für verschiedene Arten von Caches (für verschiedene Arten von Speicher-Engines) an - Sie sollten nicht zulassen, dass dieser Cache ausgetauscht wird.

Testen Sie
Unterm Strich - sollte es sehr einfach sein, nur diese mit Client zu testen (ich weiß nicht, Perl DBI, es könnte, aber ich bezweifle es, etwas tun, das mysql alles zu laden zwingt auf vorbereiten). Wie auch immer ... testen Sie es:

Wenn Sie tatsächlich eine Vorbereitung auf SELECT SQL_NO_CACHE million_rows FROM table und dann holen Sie sich nur wenige Zeilen von Millionen. Sie sollten dann die Leistung mit SELECT SQL_NO_CACHE only_fetched_rows FROM table vergleichen und sehen, wie das geht. Wenn die Leistung vergleichbar (und schnell) ist, dann glaube ich, dass Sie den Bluff Ihres Kollegen anrufen können.

Auch wenn Sie Protokoll der Anweisungen aktivieren, die tatsächlich an mysql ausgegeben werden, und uns ein Transkript davon geben, dann können wir (nicht perl Leute) definitivere Antwort auf geben, was mysql tun würde.

Verwandte Themen