2015-04-17 11 views
13

Ho un dataframe con circa 155.000 righe e 12 colonne. Se lo esporto in csv con dataframe.to_csv, l'output è un file da 11 MB (che viene prodotto immediatamente).panda python to_sql con sqlalchemy: come velocizzare l'esportazione in MS SQL?

Se, tuttavia, esporto su un Microsoft SQL Server con il metodo to_sql, sono necessari tra 5 e 6 minuti! Nessuna colonna è testo: solo int, float, bool e date. Ho visto casi in cui i driver ODBC impostano nvarchar (max) e questo rallenta il trasferimento dei dati, ma non può essere il caso qui.

Qualche suggerimento su come velocizzare il processo di esportazione? Prendendo 6 minuti per esportare 11 MB di dati, la connessione ODBC diventa praticamente inutilizzabile.

Grazie!

Il mio codice è:

import pandas as pd 
from sqlalchemy import create_engine, MetaData, Table, select 
ServerName = "myserver" 
Database = "mydatabase" 
TableName = "mytable" 

engine = create_engine('mssql+pyodbc://' + ServerName + '/' + Database) 
conn = engine.connect() 

metadata = MetaData(conn) 

my_data_frame.to_sql(TableName,engine) 
+0

l'unica cosa che mi viene in mente è quello di esportare solo la struttura, vale a dire i nomi delle colonne ei tipi di dati, ma nessuna riga, a S QL, quindi esportare il file in CSV e utilizzare qualcosa come la procedura guidata di importazione/esportazione per aggiungere il file CSV alla tabella SQL. In questo modo non devo definire nuovamente tutti i tipi di colonna; questo è importante perché gli strumenti di importazione tendono a leggere le prime x righe per indovinare i tipi di dati e, se le prime file sono tutte NULL, l'ipotesi sarà errata. Tuttavia, resta il fatto che il metodo to_sql è praticamente inutilizzabile a parte le tabelle minuscole. Lo hai già sperimentato con altri database? –

+1

Ho provato lo stesso a casa, con un SQL Server Express in esecuzione sul mio stesso PC, e python ha impiegato 2 minuti per trasferire un dataframe di 1 milione di righe x 12 colonne di numeri casuali in SQL (dimensioni in CSV = 228 MB). Non super veloce ma accettabile. Ci sono voluti 6 minuti (per un file molto più piccolo) su un PC da lavoro connesso a un server SQL a poche miglia di distanza. Sai se esiste qualche parametro in panda, sqlalchemy o pyodbc per accelerare il trasferimento? Mi collego molto a quello stesso server SQL con molti altri strumenti, e non è mai così lento. Grazie! –

+1

Chiunque? Ho anche verificato che il metodo pandas.read_sql_table è ragionevolmente veloce. È solo la scrittura che è lenta, anche quando si scrive un tavolo senza vincoli. Qualche idea? Non posso essere l'unico che abbia mai sperimentato questo, eppure non trovo alcuna documentazione su questo in linea ... :( –

risposta

6

Il metodo DataFrame.to_sql genera le istruzioni INSERT per il connettore ODBC che poi viene trattato dal connettore ODBC come inserti regolari.

Quando questo è lento, non è colpa dei panda.

Salvare l'output del metodo DataFrame.to_sql in un file, quindi la riproduzione di quel file su un connettore ODBC richiederà lo stesso tempo.

Il modo corretto di massa importare i dati in un database è quello di generare un file CSV e quindi utilizzare un comando di caricamento, che nel sapore MS di database SQL si chiama BULK INSERT

Ad esempio:

BULK INSERT mydatabase.myschema.mytable 
FROM 'mydatadump.csv'; 

il riferimento sintassi è la seguente:

BULK INSERT 
    [ database_name . [ schema_name ] . | schema_name . ] [ table_name | view_name ] 
     FROM 'data_file' 
    [ WITH 
    ( 
    [ [ , ] BATCHSIZE = batch_size ] 
    [ [ , ] CHECK_CONSTRAINTS ] 
    [ [ , ] CODEPAGE = { 'ACP' | 'OEM' | 'RAW' | 'code_page' } ] 
    [ [ , ] DATAFILETYPE = 
     { 'char' | 'native'| 'widechar' | 'widenative' } ] 
    [ [ , ] FIELDTERMINATOR = 'field_terminator' ] 
    [ [ , ] FIRSTROW = first_row ] 
    [ [ , ] FIRE_TRIGGERS ] 
    [ [ , ] FORMATFILE = 'format_file_path' ] 
    [ [ , ] KEEPIDENTITY ] 
    [ [ , ] KEEPNULLS ] 
    [ [ , ] KILOBYTES_PER_BATCH = kilobytes_per_batch ] 
    [ [ , ] LASTROW = last_row ] 
    [ [ , ] MAXERRORS = max_errors ] 
    [ [ , ] ORDER ({ column [ ASC | DESC ] } [ ,...n ]) ] 
    [ [ , ] ROWS_PER_BATCH = rows_per_batch ] 
    [ [ , ] ROWTERMINATOR = 'row_terminator' ] 
    [ [ , ] TABLOCK ] 
    [ [ , ] ERRORFILE = 'file_name' ] 
    )] 
+3

Chi è interessato a fare un BULK INSERT in SQL Server tramite Python potrebbe anche essere interessato a dare un'occhiata a [la mia risposta a una domanda correlata] (http://stackoverflow.com/a/29649340/2144390). –