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


问题内容

我将通过这篇文章对SQLAlchemy的批量插入性能。我试图在基准测试中指定的各种方法-
,。SQLAlchemy ORM bulk_insert_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)))

使用这种方法,我在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 Server2008。如果我错过任何其他详细信息,请告诉我。

原始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)

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