【问题标题】:Python+MySQL - Bulk InsertPython+MySQL - 批量插入
【发布时间】:2011-06-26 03:41:34
【问题描述】:

我正在使用 Python 中的 MySQLdb 模块与数据库进行交互。我的情况是有一个非常大的列表(数万个元素),我需要将其作为行插入到表中。

我现在的解决方案是生成一个大的INSERT 语句作为字符串并执行它。

有没有更聪明的方法?

【问题讨论】:

    标签: python mysql


    【解决方案1】:

    有一个更聪明的方法。

    批量插入的问题在于,默认情况下 autocommit is enabled 会导致每个 insert 语句在下一次插入开始之前被保存到稳定存储中。

    如手册页所述:

    默认情况下,MySQL 使用自动提交运行 模式启用。这意味着尽快 当你执行一个语句时 更新(修改)表,MySQL 将更新存储在磁盘上以进行更新 永恒的。要禁用自动提交模式, 使用以下语句:

    SET autocommit=0; 
    

    禁用后 通过设置自动提交模式 自动提交变量为零,更改 到事务安全表(例如 InnoDB、BDB 或 NDBCLUSTER 的那些) 不会立即永久化。 您必须使用 COMMIT 来存储您的 更改磁盘或 ROLLBACK 以忽略 变化。

    这是 RDBM 系统的一个相当普遍的特征,它假定数据库完整性是最重要的。它确实使批量插入每次插入需要 1 秒而不是 1 毫秒。制作超大插入语句的替代方法试图实现这个单一的提交,但有可能使 SQL 解析器过载。

    【讨论】:

    • 从 1.2.0 开始,MySQLdb 默认禁用自动提交,这是 DB-API 标准 (PEP-249) 的要求。来源:mysql-python.sourceforge.net/FAQ.html
    • 如果您觉得您的插入仍然比应有的速度慢,请确保同时调整您的 mysql 服务器设置。在我的情况下,我的 innodb_buffer_pool_size 对于我的事务大小来说太小了,通过提高它,我实现了 +40% 的批量插入加速。见:dev.mysql.com/doc/refman/5.7/en/innodb-buffer-pool.html
    【解决方案2】:

    如果您必须插入大量数据,为什么要将所有数据都插入一个 insert? (这将不必要地增加你的记忆力来制作这个大的insert 字符串以及在执行它时。如果你要插入的数据非常大,这也不是一个很好的解决方案。)

    为什么不将每个insert 命令放入数据库中,然后使用for...loop 放入所有行并最终提交所有更改?

    con = mysqldb.connect(
                            host="localhost",
                            user="user",
                            passwd="**",
                            db="db name"
                         )
    cur = con.cursor()
    
    for data in your_data_list:
        cur.execute("data you want to insert: %s" %data)
    
    con.commit()
    con.close()
    

    (相信我,这真的很快,但如果你得到较慢的结果,那么这意味着你的autocommit 必须是True。按照msw 所说,将它设置为False。)

    【讨论】:

    • 如果每次插入都有一个语句,会不会很慢?我不介意使用内存。它只会是兆字节,所以我不担心。
    • 不,这不会很慢,这就是我想说的......只要你没有在循环之间提交。两个都试试看你信不信……
    • 我不知道,因为我不使用 MYISAM,但如果是这样,您可以通过从 mysql shell 执行此行 SET autocommit = 0; 来关闭提交(或者这样做在你的 python 程序中使用cur.execute('SET autocommit = 0'); con.commit())
    • 我意识到这已经很老了,也许在写它的时候情况并非如此,但文档建议使用多行插入来减少通信开销。 dev.mysql.com/doc/refman/5.5/en/…
    • 只是一个快速的旁注:当想要像这样向插入语句添加数据时:for data in your_data_list: cur.execute("data you want to insert: %s" %data),打开了 SQL 注入攻击的闸门。最好使用以下内容:for data in your_data_list: cur.execute("data you want to insert: %s",item 1, item 2)(SQL 语句字符串后面的每个逗号将用该项目替换 SQL 字符串中的 ?)请参阅“插入数据”下的 mkleehammer.github.io/pyodbc 快乐编码!
    【解决方案3】:

    只要您将其作为单个 INSERT 而不是数千个单独的插入,那么是的,这是最好的方法。注意不要超过 mysqls 的最大数据包大小,并在必要时进行调整。例如,这将服务器数据包最大设置为 32Mb。您也需要在客户端上执行相同的操作。

    mysqld --max_allowed_packet=32M
    

    【讨论】:

    • 这是对交易机制的破解,它解决的是症状而不是原因
    • 你能扩展一下吗?或者说你会怎么做?
    猜你喜欢
    • 1970-01-01
    • 2018-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 2012-12-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多