2015-11-20 28 views
5

できるだけ早くSQL Serverデータベースに挿入しようとしている、74個の比較的大きなパンダのデータフレーム(約34,600行と8列)があります。いくつかの調査を行った後、私は、良いOLE pandas.to_sql機能は、私が取った最初のアプローチであったSQL Serverデータベースへのそのような大きな挿入には適していないことを学びました(非常に遅い - アプリケーションが完了するまでに約1時間。大きなパンダのデータフレームをSQL Serverデータベースに書き込む

私はではなく、SQLAlchemyののコアを使用しようとしています:mysqlデータベースを使用している場合)

This article、および他の多くのStackOverflowの記事をしかし私はバリケードを打ってきました、正しい方向に私を指している役立っています上記のリンクで説明されている理由でORM。だから、私は、辞書にデータフレームを変換pandas.to_dictを使用して、​​とinsert()をしています:

self._session_factory.engine.execute(
    TimeSeriesResultValues.__table__.insert(), 
    data) 
# 'data' is a list of dictionaries. 

問題は、インサートは、任意の値を取得していないことである - 彼らは、空の括弧の束として表示され、Iこのエラーが表示される:

(pyodbc.IntegretyError) ('23000', "[23000] [FreeTDS][SQL Server]Cannot 
insert the value NULL into the column... 

私が渡した辞書のリストには値があります。なぜ値が表示されないのかわかりません。

EDITは:

ここで私はのオフつもり例です:あなたは、SQLAlchemyのは、実際にSQL Serverの一括インポートを実装していないため、私はいくつかの悲しいニュースを持っている

def test_sqlalchemy_core(n=100000): 
    init_sqlalchemy() 
    t0 = time.time() 
    engine.execute(
     Customer.__table__.insert(), 
     [{"name": 'NAME ' + str(i)} for i in range(n)] 
    ) 
    print("SQLAlchemy Core: Total time for " + str(n) + 
     " records " + str(time.time() - t0) + " secs") 
+0

*約4分のMySQLデータベースを使用して* ...そう 'to_sqlは()'だけで接続が可能なソリューションです。 MySQLと比較してMSSQLが遅いですか?どのODBC APIを使用していますか?データベースサーバーはローカルまたはリモートのどちらですか?一時テーブルのインポートを検討し、最終的なテーブルに移行します。 – Parfait

+0

@Parfait: '' 'to_sql()' ''を使用すると、MySQLでは許容可能なパフォーマンスが得られますが、MSSQLでは許容されません。私はpyodbcを使用しています。データベースはリモートであるため、CSVファイルに書き込んでから、raw SQLコードを使用して一括挿入することは、この状況では実際には機能しません。さらに、ユーザーには一括管理権限が必要ですが、このアプリケーションのユーザーにとっては必ずしも可能ではない可能性があります。 – denvaar

+1

odbcドライバをバイパスし、厳密にPython APIを使用することを検討してください - [pmyssl](http://www.pymssql.org/en/latest/)そしてMySQL ODBC API? pymysql?両方の同じテーブル構造とデータ型?同じ数のレコード?本当にこれを調べてください。どちらも高水準のエンタープライズRDMSであり、その広い範囲(4分〜60分)を実行すべきではありません。 – Parfait

答えて

7

、それはです実際にはto_sqlが行っているのと同じ、遅い個別のINSERT文を実行します。あなたの最善の策は、bcpコマンドラインツールを使って何かを試してみることです。ここで私は過去に使用したスクリプトが、無保証されています

from subprocess import check_output, call 
import pandas as pd 
import numpy as np 
import os 

pad = 0.1 
tablename = 'sandbox.max.pybcp_test' 
overwrite=True 
raise_exception = True 
server = 'P01' 
trusted_connection= True 
username=None 
password=None 
delimiter='|' 
df = pd.read_csv('D:/inputdata.csv', encoding='latin', error_bad_lines=False) 



def get_column_def_sql(col): 
    if col.dtype == object: 
     width = col.str.len().max() * (1+pad) 
     return '[{}] varchar({})'.format(col.name, int(width)) 
    elif np.issubdtype(col.dtype, float): 
     return'[{}] float'.format(col.name) 
    elif np.issubdtype(col.dtype, int): 
     return '[{}] int'.format(col.name) 
    else: 
     if raise_exception: 
     raise NotImplementedError('data type {} not implemented'.format(col.dtype)) 
     else: 
     print('Warning: cast column {} as varchar; data type {} not implemented'.format(col, col.dtype)) 
     width = col.str.len().max() * (1+pad) 
     return '[{}] varchar({})'.format(col.name, int(width)) 

def create_table(df, tablename, server, trusted_connection, username, password, pad):   
    if trusted_connection: 
     login_string = '-E' 
    else: 
     login_string = '-U {} -P {}'.format(username, password) 

    col_defs = [] 
    for col in df: 
     col_defs += [get_column_def_sql(df[col])] 

    query_string = 'CREATE TABLE {}\n({})\nGO\nQUIT'.format(tablename, ',\n'.join(col_defs))  
    if overwrite == True: 
     query_string = "IF OBJECT_ID('{}', 'U') IS NOT NULL DROP TABLE {};".format(tablename, tablename) + query_string 


    query_file = 'c:\\pybcp_tempqueryfile.sql' 
    with open (query_file,'w') as f: 
     f.write(query_string) 

    if trusted_connection: 
     login_string = '-E' 
    else: 
     login_string = '-U {} -P {}'.format(username, password) 

    o = call('sqlcmd -S {} {} -i {}'.format(server, login_string, query_file), shell=True) 
    if o != 0: 
     raise BaseException("Failed to create table") 
    # o = call('del {}'.format(query_file), shell=True) 


def call_bcp(df, tablename): 
    if trusted_connection: 
     login_string = '-T' 
    else: 
     login_string = '-U {} -P {}'.format(username, password) 
    temp_file = 'c:\\pybcp_tempqueryfile.csv' 

    #remove the delimiter and change the encoding of the data frame to latin so sql server can read it 
    df.loc[:,df.dtypes == object] = df.loc[:,df.dtypes == object].apply(lambda col: col.str.replace(delimiter,'').str.encode('latin')) 
    df.to_csv(temp_file, index = False, sep = '|', errors='ignore') 
    o = call('bcp sandbox.max.pybcp_test2 in c:\pybcp_tempqueryfile.csv -S "localhost" -T -t^| -r\n -c') 
+0

応答をありがとう - ファイルを作成することがこの特定の状況のた​​めに働くかどうか私は知らない。 – denvaar

+0

なぜサポートしていないのですか? – denvaar

関連する問題