2013-08-07 8 views
17

Ich habe Probleme beim Abfragen einer Tabelle von> 5 Millionen Datensätze aus meiner MS SQL Server-Datenbank. Ich möchte in der Lage sein, alle Datensätze auszuwählen, aber mein Code scheint zu versagen, wenn ich zu viele Daten in den Speicher auswähle.Wie erstelle ich einen großen Pandas-Datenrahmen aus einer SQL-Abfrage, ohne den Arbeitsspeicher zu verlieren?

Dies funktioniert:

import pandas.io.sql as psql 
sql = "SELECT TOP 1000000 * FROM MyTable" 
data = psql.read_frame(sql, cnxn) 

... aber das funktioniert nicht:

sql = "SELECT TOP 2000000 * FROM MyTable" 
data = psql.read_frame(sql, cnxn) 

Es diesen Fehler zurückgibt:

File "inference.pyx", line 931, in pandas.lib.to_object_array_tuples 
(pandas\lib.c:42733) Memory Error 

ich here gelesen, dass ein ähnliches Problem existiert beim Erstellen eines Datenrahmens aus einer CSV-Datei, und die Umgehung ist die Verwendung der "Iterator" und "Chunksi" ze 'Parameter wie folgt:

read_csv('exp4326.csv', iterator=True, chunksize=1000) 

Gibt es eine ähnliche Lösung für die Abfrage von einer SQL-Datenbank? Wenn nicht, was ist die bevorzugte Lösung? Muss ich die Datensätze in Chunks auf andere Weise einlesen? Ich lese ein wenig Diskussion here für die Arbeit mit großen Datasets in Pandas, aber es scheint wie viel Arbeit, eine SELECT * -Abfrage auszuführen. Sicherlich gibt es einen einfacheren Ansatz.

+0

Wie viel Speicher haben Sie haben? –

+0

@PhillipCloud meine Maschine hat 4 GB RAM. – slizb

+0

Abhängig vom 'dtype' Ihrer Spalten und der Anzahl der Spalten können Sie problemlos 4GB erreichen. ZB –

Antwort

18

Update: Überprüfen Sie die Antwort unten, da Pandas jetzt integrierte Unterstützung für Chunked Loading bietet.

Sie könnten einfach versuchen, die Eingabetabelle Chunk-weise und montieren Ihren vollständigen Datenrahmen aus den einzelnen Stücken danach wie folgt zu lesen:

import pandas as pd 
import pandas.io.sql as psql 
chunk_size = 10000 
offset = 0 
dfs = [] 
while True: 
    sql = "SELECT * FROM MyTable limit %d offset %d order by ID" % (chunk_size,offset) 
    dfs.append(psql.read_frame(sql, cnxn)) 
    offset += chunk_size 
    if len(dfs[-1]) < chunk_size: 
    break 
full_df = pd.concat(dfs) 

Es ist auch möglich sein könnte, dass der gesamte Datenrahmen ist einfach zu groß, um in den Speicher zu passen, in diesem Fall haben Sie keine andere Möglichkeit, als die Anzahl der Zeilen oder Spalten einzuschränken, die Sie auswählen.

+0

-Danke, ich werde das ausprobieren, obwohl ich befürchte, dass der Speicherplatz tatsächlich mein Problem sein könnte. Außerdem, da ich MS SQL-Server2008 verwende, sind die LIMIT- und OFFSET-SQL-Optionen für mich nicht verfügbar. Andere sollten [hier] (http://stackoverflow.com/questions/187998/row-offset-in-sql-server) für die spezifische Lösung ihres Setups wissen. – slizb

+2

Sie können diese df auch in eine HDF5-Datei schreiben (Die Frage, auf die Sie verwiesen haben, verwendet auch die Dokumente, indem Sie die Tabellen anhängen: http://pandas.pydata.org/pandas-docs/dev/io.html#hdf5-pytables. Dann lesen Sie die Abschnitte (oder wiederholen Sie sie nach Bedarf). ; HDF5 viel kompakter als SQL für Daten – Jeff

1

Eine grundlegende Lösung zu meiner Frage: mehr Speicher erhalten:

Meine Firma mit 64 GB RAM einen Hochleistungs-Computer hat (16x, die auf meinem Rechner). Ich habe versucht, mich an diese Maschine zu wenden und meinen Code darauf zu schreiben. Zu meiner Freude funktionierte es ohne Speicherfehler!

Dies wird nicht eine praktikable Lösung für alle mit diesem Speicherproblem sein, aber wenn Sie die Option haben, kann es die Arbeit erledigt bekommen.

HDF5 scheint der beste Weg für eine dauerhaftere Lösung zu sein, wie von @Jeff beschrieben.

20

Wie in einem Kommentar erwähnt, von Pandas beginnend 0,15, haben Sie eine chunksize Option in read_sql zu lesen und die Abfrage Chunk Chunk zu verarbeiten:

sql = "SELECT * FROM My_Table" 
for chunk in pd.read_sql_query(sql , engine, chunksize=5): 
    print(chunk) 

Referenz: http://pandas.pydata.org/pandas-docs/version/0.15.2/io.html#querying

+0

** Dies ist der Weg **, um Probleme zu behandeln, wo RAM-Größe zelusp

+1

ist es möglich, das Lesen einiger Chunks zu überspringen? – denfromufa

+0

ZB ein Schlüsselwort-Argument skip_chunks = Anzahl_von_chunks, das kann Überspringe die ersten paar Blöcke, ohne sie auch nur zu lesen. Der Anwendungsfall liest das Ende oder die Mitte der SQL-Tabelle mit über 1 Million Zeilen, ohne SQL-Abfrage oder SQLalchemy zu verwenden. – denfromufa

Verwandte Themen