web-dev-qa-db-ja.com

大規模な書き込みPandas DataFrames to SQL Server database

74の比較的大きなPandas DataFrames(約34,600行と8列))をSQL Serverデータベースにできるだけ早く挿入しようとしています。いくつかの調査を行った後、 ole _pandas.to_sql_関数は、SQL Serverデータベースへのこのような大規模な挿入には適していません。これは、私が取った最初のアプローチでした(非常に遅く、アプリケーションが完了するまでに約1時間、mysqlデータベースを使用する場合は約4分です)。

この記事 、および他の多くのStackOverflow投稿が正しい方向を示すのに役立ちましたが、私は障害にぶつかりました:

上記のリンクで説明されている理由により、ORMではなくSQLAlchemyのコアを使用しようとしています。したがって、私は_pandas.to_dict_を使用してデータフレームを辞書に変換し、次にexecute()およびinsert()を実行します。

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

問題は、挿入が値を取得していないことです。それらは空の括弧の束として表示され、次のエラーが発生します。

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

渡した辞書のリストに値があるので、値が表示されない理由を理解できません。

編集:

ここに私が出かける例があります:

_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")
_
11
denvaar

悲しいお知らせがあります。SQLAlchemyは実際にはSQL Serverの一括インポートを実装していません。実際には、to_sqlが実行しています。あなたの最善の策は、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')
12
maxymoo

これは、SQLAchemy ver:1.3.0で最近更新されました。誰かが知る必要がある場合に備えて。 dataframe.to_sqlステートメントをはるかに速くする必要があります。

https://docs.sqlalchemy.org/en/latest/changelog/migration_13.html#support-for-pyodbc-fast-executemany

engine = create_engine( "mssql + pyodbc:// scott:tiger @ mssql2017:1433/test?driver = ODBC + Driver + 13 + for + SQL + Server"、fast_executemany = True

3
Hung Nguyen