sqlalchemy 批量插入比构建原始文件慢 SQL
sqlalchemy bulk insert is slower than building raw SQL
我正在经历 this article on the sqlalchemy bulk insert performance. I tried various approaches specified in the benchmark test - SQLAlchemy ORM bulk_insert_mappings()
, SQLAlchemy Core
. Unfortunately for inserting 1000 rows all these methods required about 1min to insert them. This is horrendously slow. I tried also the approach specified here - 这需要我构建一个大型 SQL 语句,例如:
INSERT INTO mytable (col1, col2, col3)
VALUES (1,2,3), (4,5,6) ..... --- up to 1000 of these
这个原始 SQL 的插入是这样的:
MySession.execute('''
insert into MyTable (e, l, a)
values {}
'''.format(",".join(my_insert_str)))
使用这种方法,我在 10-11 秒内将性能提高了 50 倍以上,达到 10000 次插入。
这是使用内置库的方法的代码。
class MyClass(Base):
__tablename__ = "MyTable"
e = Column(String(256), primary_key=True)
l = Column(String(6))
a = Column(String(20), primary_key=True)
def __repr__(self):
return self.e + " " + self.a+ " " + self.l
.......
dict_list = []
for i, row in chunk.iterrows():
dict_list += [{"e" : row["e"], "l" : l, "a" : a}]
MySession.execute(
Myclass.__table__.insert(),
dict_list
)
这是我连接到数据库的方式。
params = urllib.quote_plus("DRIVER={SQL Server Native Client 10.0};SERVER=servername;DATABASE=dbname;UID=user;PWD=pass")
engine = create_engine("mssql+pyodbc:///?odbc_connect=%s" % params )
MySession.configure(bind=engine, autoflush=False, expire_on_commit=False)
我的设置是否有问题导致性能下降如此之多?我尝试使用不同的数据库驱动程序——pyodbc 和 pymssql。无论我尝试什么,我都无法接近他们在文章中声称的数字,即:
SQLAlchemy ORM: Total time for 100000 records 2.192882061 secs
SQLAlchemy ORM pk given: Total time for 100000 records 1.41679310799 secs
SQLAlchemy ORM bulk_save_objects(): Total time for 100000 records 0.494568824768 secs
SQLAlchemy ORM bulk_insert_mappings(): Total time for 100000 records 0.325763940811 secs
SQLAlchemy Core: Total time for 100000 records 0.239127874374 secs
sqlite3: Total time for 100000 records 0.124729156494 sec
我正在连接到 MS SQL Server 2008。如果我遗漏了任何其他详细信息,请告诉我。
原始 SQL 方法的问题在于它不是 SQL 注入安全的。因此,如果您对如何解决此问题有建议,那也会非常有帮助:)。
你在做
MySession.execute(
Myclass.__table__.insert(),
dict_list
)
使用 executemany()
。它与 INSERT INTO ... VALUES ...
不同。要使用 VALUES
,请执行:
MySession.execute(
Myclass.__table__.insert().values(dict_list)
)
附带说明,SQL 注入问题使用参数解决:
MySession.execute('''
insert into MyTable (e, l, a)
values (?, ?, ?), (?, ?, ?), ...
''', params)
这里的要点是您没有比较等效的结构。您没有在 SQLAlchemy 生成的查询中使用 VALUES
,但您在文本 SQL 中,并且您没有在文本 SQL 中使用参数化,但您在 SQLAlchemy 生成的查询中。如果您为已执行的 SQL 语句打开日志记录,您将确切地看到不同之处。
我正在经历 this article on the sqlalchemy bulk insert performance. I tried various approaches specified in the benchmark test - SQLAlchemy ORM bulk_insert_mappings()
, SQLAlchemy Core
. Unfortunately for inserting 1000 rows all these methods required about 1min to insert them. This is horrendously slow. I tried also the approach specified here - 这需要我构建一个大型 SQL 语句,例如:
INSERT INTO mytable (col1, col2, col3)
VALUES (1,2,3), (4,5,6) ..... --- up to 1000 of these
这个原始 SQL 的插入是这样的:
MySession.execute('''
insert into MyTable (e, l, a)
values {}
'''.format(",".join(my_insert_str)))
使用这种方法,我在 10-11 秒内将性能提高了 50 倍以上,达到 10000 次插入。
这是使用内置库的方法的代码。
class MyClass(Base):
__tablename__ = "MyTable"
e = Column(String(256), primary_key=True)
l = Column(String(6))
a = Column(String(20), primary_key=True)
def __repr__(self):
return self.e + " " + self.a+ " " + self.l
.......
dict_list = []
for i, row in chunk.iterrows():
dict_list += [{"e" : row["e"], "l" : l, "a" : a}]
MySession.execute(
Myclass.__table__.insert(),
dict_list
)
这是我连接到数据库的方式。
params = urllib.quote_plus("DRIVER={SQL Server Native Client 10.0};SERVER=servername;DATABASE=dbname;UID=user;PWD=pass")
engine = create_engine("mssql+pyodbc:///?odbc_connect=%s" % params )
MySession.configure(bind=engine, autoflush=False, expire_on_commit=False)
我的设置是否有问题导致性能下降如此之多?我尝试使用不同的数据库驱动程序——pyodbc 和 pymssql。无论我尝试什么,我都无法接近他们在文章中声称的数字,即:
SQLAlchemy ORM: Total time for 100000 records 2.192882061 secs
SQLAlchemy ORM pk given: Total time for 100000 records 1.41679310799 secs
SQLAlchemy ORM bulk_save_objects(): Total time for 100000 records 0.494568824768 secs
SQLAlchemy ORM bulk_insert_mappings(): Total time for 100000 records 0.325763940811 secs
SQLAlchemy Core: Total time for 100000 records 0.239127874374 secs
sqlite3: Total time for 100000 records 0.124729156494 sec
我正在连接到 MS SQL Server 2008。如果我遗漏了任何其他详细信息,请告诉我。
原始 SQL 方法的问题在于它不是 SQL 注入安全的。因此,如果您对如何解决此问题有建议,那也会非常有帮助:)。
你在做
MySession.execute(
Myclass.__table__.insert(),
dict_list
)
使用 executemany()
。它与 INSERT INTO ... VALUES ...
不同。要使用 VALUES
,请执行:
MySession.execute(
Myclass.__table__.insert().values(dict_list)
)
附带说明,SQL 注入问题使用参数解决:
MySession.execute('''
insert into MyTable (e, l, a)
values (?, ?, ?), (?, ?, ?), ...
''', params)
这里的要点是您没有比较等效的结构。您没有在 SQLAlchemy 生成的查询中使用 VALUES
,但您在文本 SQL 中,并且您没有在文本 SQL 中使用参数化,但您在 SQLAlchemy 生成的查询中。如果您为已执行的 SQL 语句打开日志记录,您将确切地看到不同之处。