Python sqlalchemy批量插入比构建原始SQL慢

Python sqlalchemy批量插入比构建原始SQL慢,python,sql-server,performance,sqlalchemy,bulkinsert,Python,Sql Server,Performance,Sqlalchemy,Bulkinsert,我将介绍sqlalchemy批量插入性能。我尝试了基准测试中指定的各种方法-SQLAlchemy ORM bulk\u insert\u mappings(),SQLAlchemy Core。不幸的是,对于插入1000行,所有这些方法都需要大约1分钟的时间来插入它们。这速度太慢了。我还尝试了指定的方法-这需要我构建一个大型SQL语句,如: INSERT INTO mytable (col1, col2, col3) VALUES (1,2,3), (4,5,6) ..... --- up to

我将介绍sqlalchemy批量插入性能。我尝试了基准测试中指定的各种方法-
SQLAlchemy ORM bulk\u insert\u mappings()
SQLAlchemy Core
。不幸的是,对于插入1000行,所有这些方法都需要大约1分钟的时间来插入它们。这速度太慢了。我还尝试了指定的方法-这需要我构建一个大型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)))
使用这种方法,我将性能提高了50倍以上,在10-11秒内插入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)
我的设置是否存在问题,从而严重降低了性能?我尝试了不同的db驱动程序——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()
。它不同于插入到。。。值…。要使用
,请执行以下操作:

MySession.execute(
    Myclass.__table__.insert().values(dict_list)
)
作为旁注,SQL注入问题是通过参数解决的:

MySession.execute('''
insert into MyTable (e, l, a)
values (?, ?, ?), (?, ?, ?), ...
''', params)

这里的要点是,您没有比较等效的构造。您没有在SQLAlchemy生成的查询中使用
值,而是在文本SQL中使用;您没有在文本SQL中使用参数化,而是在SQLAlchemy生成的查询中使用。如果您打开已执行SQL语句的日志记录,您将看到完全不同的地方。

我建议您阅读:,仅供参考;)我更倾向于建议阅读,这是关于pyodbc的一个长期存在的问题,对于大型插入,执行速度非常慢。尽管批量数据处理不是其中之一,但ORM也有其地位。并不是说它适用于所有情况,尤其是在这里,而是编译
insert().values()
。执行本身比预期的要快。我们应该对此进行更多的研究。@IljaEverilä这是一个很好的观点。对于这样的大型数据集,我倾向于将CSV流式传输到
COPY
,就像您的答案一样,只是不在内存中生成整个文件。但是,对于约1k个条目,使用
值的开销应该相对较小。同意。似乎pyodbc已经做到了。@univerio感谢您的回答,我实际上最终使用了参数来阻止SQL注入,到目前为止,我认为这给了我最好的性能。很高兴看到你也提出了这个建议!我将再次检查.insert().values(dict_list),尽管我现在对任何内置方法都有点怀疑:DIt仍然很奇怪性能文章是如何获得的