代码之家  ›  专栏  ›  技术社区  ›  Anton Belev

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

  •  5
  • Anton Belev  · 技术社区  · 8 年前

    我正在经历 this article 关于sqlalchemy批量插入性能。我尝试了基准测试中指定的各种方法- SQLAlchemy ORM bulk_insert_mappings() , SQLAlchemy Core 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)))
    

    使用这种方法,我将性能提高了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
    

    原始SQL方法的问题是它不是SQL注入安全的。因此,如果你有如何解决这个问题的建议,它也将非常有用:)。

    1 回复  |  直到 5 年前
        1
  •  13
  •   univerio    8 年前

    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生成的查询中,但在文本SQL中,在文本SQL中没有使用参数化,但在SQLAlchemy生成的查询中。如果打开已执行SQL语句的日志记录,您将清楚地看到不同之处。