以下は、助けて欲しい私のコードです。 1,300,000行以上実行する必要があるため、最大300,000行を挿入するには40分が必要です。
一括挿入は速度を上げるためのルートですか?それとも、for data in reader:
部分を介して行を繰り返し処理しているからですか?
#Opens the prepped csv file
with open (os.path.join(newpath,outfile), 'r') as f:
#hooks csv reader to file
reader = csv.reader(f)
#pulls out the columns (which match the SQL table)
columns = next(reader)
#trims any extra spaces
columns = [x.strip(' ') for x in columns]
#starts SQL statement
query = 'bulk insert into SpikeData123({0}) values ({1})'
#puts column names in SQL query 'query'
query = query.format(','.join(columns), ','.join('?' * len(columns)))
print 'Query is: %s' % query
#starts curser from cnxn (which works)
cursor = cnxn.cursor()
#uploads everything by row
for data in reader:
cursor.execute(query, data)
cursor.commit()
私は列ヘッダーを意図的に動的に選択しています(可能な限りPythonコードを作成したいので)。
SpikeData123はテーブル名です。
更新:@SimonLangのコメントで述べたように、SQL Server 2017以降のBULK INSERT
は、CSVファイルのテキスト修飾子をサポートしているようです(参照: here )。
BULK INSERTは、ほぼ確実にmuch行ごとにソースファイルを読み取り、各行に対して通常のINSERTを実行するよりも高速です。ただし、BULK INSERTとBCPの両方には、テキスト修飾子を参照できないという点でCSVファイルに関する重要な制限があります(参照: here )。つまり、CSVファイルにnotに修飾テキスト文字列が含まれていない場合...
1,Gord Thompson,2015-04-15
2,Bob Loblaw,2015-04-07
...その後、BULK INSERTできますが、テキスト修飾子が含まれている場合(一部のテキスト値にコンマが含まれているため)...
1,"Thompson, Gord",2015-04-15
2,"Loblaw, Bob",2015-04-07
... BULK INSERTは処理できません。それでも、このようなCSVファイルをパイプ区切りファイルに前処理する方が全体的に速いかもしれません...
1|Thompson, Gord|2015-04-15
2|Loblaw, Bob|2015-04-07
...またはタブ区切りファイル(→
はタブ文字を表します)...
1→Thompson, Gord→2015-04-15
2→Loblaw, Bob→2015-04-07
...そして、そのファイルを一括挿入します。後者の(タブ区切り)ファイルの場合、BULK INSERTコードは次のようになります。
import pypyodbc
conn_str = "DSN=myDb_SQLEXPRESS;"
cnxn = pypyodbc.connect(conn_str)
crsr = cnxn.cursor()
sql = """
BULK INSERT myDb.dbo.SpikeData123
FROM 'C:\\__tmp\\biTest.txt' WITH (
FIELDTERMINATOR='\\t',
ROWTERMINATOR='\\n'
);
"""
crsr.execute(sql)
cnxn.commit()
crsr.close()
cnxn.close()
注:コメントで述べたように、BULK INSERT
ステートメントの実行は、SQL Serverインスタンスがソースファイルを直接読み取ることができる場合にのみ適用できます。ソースファイルがリモートクライアントにある場合は、 this answer を参照してください。
別の回答のコメントに記載されているように、T-SQL BULK INSERT
コマンドは、インポートするファイルがSQL Serverインスタンスと同じマシン上にあるか、SQLが実行されるSMB/CIFSネットワークの場所にある場合にのみ機能しますサーバーインスタンスが読み取ることができます。したがって、ソースファイルがリモートクライアント上にある場合には適用できない場合があります。
pyodbc 4.0.19は、その場合に役立つかもしれない Cursor#fast_executemany 機能を追加しました。 fast_executemany
はデフォルトで「オフ」であり、次のテストコード...
cnxn = pyodbc.connect(conn_str, autocommit=True)
crsr = cnxn.cursor()
crsr.execute("TRUNCATE TABLE fast_executemany_test")
sql = "INSERT INTO fast_executemany_test (txtcol) VALUES (?)"
params = [(f'txt{i:06d}',) for i in range(1000)]
t0 = time.time()
crsr.executemany(sql, params)
print(f'{time.time() - t0:.1f} seconds')
...テストマシンで実行するのに約22秒かかりました。 crsr.fast_executemany = True
を追加するだけです...
cnxn = pyodbc.connect(conn_str, autocommit=True)
crsr = cnxn.cursor()
crsr.execute("TRUNCATE TABLE fast_executemany_test")
crsr.fast_executemany = True # new in pyodbc 4.0.19
sql = "INSERT INTO fast_executemany_test (txtcol) VALUES (?)"
params = [(f'txt{i:06d}',) for i in range(1000)]
t0 = time.time()
crsr.executemany(sql, params)
print(f'{time.time() - t0:.1f} seconds')
...実行時間が1秒強に短縮されました。
はい、一括挿入は、大きなファイルをDBにロードするための正しいパスです。一見すると、時間がかかる理由は、あなたが言及したように、ファイルからデータの各行をループしているということです。その名前は、データのチャックを挿入するために使用されることを暗示していることを覚えておいてください。ループを削除して、再試行します。
また、私には正しく表示されないため、一括挿入の構文を再確認します。 pyodbcによって生成されたsqlを確認してください。通常の挿入のみを実行しているのではないかと思う
あるいは、それでもまだ遅い場合は、SQLから直接バルク挿入を使用して、ファイル全体をバルク挿入で一時テーブルにロードしてから、関連する列を適切なテーブルに挿入します。または、一括挿入とbcpを組み合わせて使用して、特定の列を挿入するか、OPENROWSETを取得します。