API WebサイトからJsonデータをダウンロードし、sqlalchemy、pyodbc、pandasのto_sql関数を使用して、そのデータをMSSQLサーバーに挿入しています。
最大10000行をダウンロードできますが、チャンクサイズを10に制限する必要があります。そうしないと、次のエラーが発生します。
DBAPIError:(pyodbc.Error)( '07002'、 '[07002] [Microsoft] [SQL Server Native Client 11.0] COUNTフィールドが正しくないか構文エラー(0)(SQLExecDirectW)')[SQL: 'INSERT INTO [TEMP_producing_entity_details]
ダウンロードする行は約5億行あり、この速度でクロールしているだけです。回避策に関するアドバイスはありますか?
おかげで、
更新:
pandas 0.23.1は、0.23.0で導入された問題のある変更を元に戻しました。ただし、生のパフォーマンスの最適なソリューションは、CSV-> bcp
アプローチのままです。
更新:
パンダ0.24.0は明らかに問題を再導入しました(参照: ここ )
(元の回答)
pandasバージョン0.23.0より前のバージョンでは、to_sql
はDataTableの行ごとに個別のINSERTを生成します。
exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6)',
N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2)',
0,N'row000'
exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6)',
N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2)',
1,N'row001'
exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6)',
N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2)',
2,N'row002'
おそらくパフォーマンスを向上させるために、pandas 0.23.0は呼び出しごとに複数の行を挿入するためのテーブル値コンストラクタを生成します
exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6),@P3 int,@P4 nvarchar(6),@P5 int,@P6 nvarchar(6)',
N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2), (@P3, @P4), (@P5, @P6)',
0,N'row000',1,N'row001',2,N'row002'
問題は、SQL Serverストアドプロシージャ(sp_prepexec
などのシステムストアドプロシージャを含む)が2100パラメータに制限されているため、DataFrameに100列ある場合、to_sql
は一度に約20行しか挿入できないことです。
必要なchunksize
を使用して計算できます
# df is an existing DataFrame
#
# limit based on sp_prepexec parameter count
tsql_chunksize = 2097 // len(df.columns)
# cap at 1000 (limit for number of rows inserted by table-value constructor)
tsql_chunksize = 1000 if tsql_chunksize > 1000 else tsql_chunksize
#
df.to_sql('tablename', engine, if_exists='replace', index=False, chunksize=tsql_chunksize)
ただし、最速のアプローチは次のようになります。
dataFrameをCSVファイル(または同様のもの)にダンプし、次に
Python SQL Server bcp
ユーティリティを呼び出して、そのファイルをテーブルにアップロードします。
Gord Thompsonの回答に基づいていくつかの変更を加えました。これにより、チャンクサイズが自動計算され、2100パラメータの制限に適合する最小の最も近い整数値に保持されます。
import math
df_num_of_cols=len(df.columns)
chunknum=math.floor(2100/df_num_of_cols)
df.to_sql('MY_TABLE',con=engine,schema='myschema',chunksize=chunknum,if_exists='append',method='multi',index=False )