Comment créer une grande pandas dataframe partir d'une requête sql sans manquer de mémoire?

j'ai du mal à interroger une table de plus de 5 millions d'enregistrements de ma base de données de serveur MS SQL. Je veux être capable de sélectionner tous les enregistrements, mais mon code semble échouer lors de la sélection de beaucoup de données dans la mémoire.

Cela fonctionne:

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

...mais cela ne fonctionne pas:

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

il renvoie cette erreur:

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

j'ai lu ici qu'un similaire il existe un problème lors de la création d'une dataframe à partir d'un fichier csv, et que la solution consiste à utiliser les paramètres 'iterator' et 'chunksize' comme ceci:

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

Existe-t-il une solution similaire pour interroger une base de données SQL? Si non, quel est le meilleur travail? Dois-je lire dans les dossiers en morceaux par une autre méthode? J'ai lu un peu de discussion ici pour travailler avec de grands ensembles de données dans pandas, mais il semble que beaucoup de travail pour exécuter une requête SELECT*. Il y a sûrement une approche plus simple.

20
demandé sur Community 2013-08-07 19:50:01

2 réponses

mise à jour: assurez-vous de vérifier la réponse ci-dessous, car Pandas dispose désormais d'un support intégré pour le chargement tronqué.

vous pourriez simplement essayer de lire le chunk-wise de la table d'entrée et assembler votre dataframe complète des pièces individuelles après, comme ceci:

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)

il est également possible que l'ensemble de la base de données soit tout simplement trop grand pour entrer en mémoire, dans ce cas vous n'aurez pas d'autre choix que de restreindre le nombre de lignes ou de colonnes que vous sélectionnez.

24
répondu ThePhysicist 2017-01-02 10:38:51

comme mentionné dans un commentaire, à partir de pandas 0.15, vous avez une option chunksize dans read_sql pour lire et traiter la requête chunk par chunk:

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

référence: http://pandas.pydata.org/pandas-docs/version/0.15.2/io.html#querying

26
répondu ksindi 2016-10-24 15:11:19