【问题标题】:Accelerating slow MySQL import using python connector使用 python 连接器加速缓慢的 MySQL 导入
【发布时间】:2023-02-10 17:58:55
【问题描述】:

我正在编写一个将大型数据库导入 MySQL 的 python 脚本。到目前为止,我使用了这种方法,它有效,但速度很慢:

importdb = "mysql -h " + DB_HOST + " -u " + DB_USER + " -p" + shlex.quote(DB_USER_PASSWORD) + " " + DB_TARGET + " < " + os.getcwd() + "\\AllPrintings.sql"
os.system(importdb)

根据this 和类似的帖子,如果在导入前更改默认设置,导入速度会更快:

SET autocommit=0;
SET unique_checks=0;
SET foreign_key_checks=0;
# <import statement here>
COMMIT;
SET unique_checks=1;
SET foreign_key_checks=1;

问题是这些设置仅与特定连接相关。当我使用 python 脚本时,我看到了两个选项,但在这两个选项中我都找不到可行的解决方案:

  1. 使用 os.system 并添加 SET 命令 - 我尝试用 ; 分隔命令但它似乎在 first 之后停止执行它们;

    #不起作用

    importdb = "mysql -h " + DB_HOST + " -u " + DB_USER + " -p" + shlex.quote(DB_USER_PASSWORD)+ "; " + "use " + DB_TARGET + "; SET autocommit=0; SET unique_checks=0; SET FOREIGN_KEY_CHECKS=0; " + "source" + os.getcwd() + "\\AllPrintings.sql; SET autocommit=1; SET unique_checks=1; SET FOREIGN_KEY_CHECKS=1;"
    os.system(importdb)
    
    1. 使用导入 mysql.connector 并添加导入语句:SET 命令有效,但无法导入

    #不起作用

    cur.execute(f"SET autocommit=0;")
    cur.execute(f"SET unique_checks=0;")
    cur.execute(f"SET FOREIGN_KEY_CHECKS=0;")
    cur.execute(DB_TARGET + ' < ' + os.getcwd() + '\\AllPrintings.sql')
    conn.commit()
    cur.execute(f"SET autocommit=1;")
    cur.execute(f"SET unique_checks=1;")
    cur.execute(f"SET FOREIGN_KEY_CHECKS=1;");
    

    我被困住了,我不知道如何进一步前进,所有帮助将不胜感激......


    编辑和解决方案

    根据下面@mrrobot.viewsource 的回答,解决方案是使用上面的命令修改导入的数据库。它将测试数据库的导入时间从 73 分钟减少到 2 分钟。我的代码:

    with open(os.getcwd() + "\\AllPrintings.sql", "r+",encoding="utf8") as f:
            content = f.read()
            f.seek(0, 0)
            f.write("SET autocommit=0;\nSET unique_checks=0;\nSET FOREIGN_KEY_CHECKS=0;" + '\n' + content)
    
    with open(os.getcwd() + "\\AllPrintings.sql", "a+", encoding="utf8") as f:
        f.write("\nSET unique_checks=1;\nSET FOREIGN_KEY_CHECKS=1;\n")
    

【问题讨论】:

    标签: python mysql mysql-connector-python


    【解决方案1】:

    您的代码存在一些问题。您是否尝试打印变量 importdb ? 这是您的脚本中发生的事情:

    问题:

    您的脚本(出于显而易见的原因评论了os.system(importdb)):

    import shlex
    import os
    
    DB_HOST="1.1.1.1"
    DB_USER="root"
    DB_USER_PASSWORD="password"
    DB_TARGET="somedb"
    
    importdb = "mysql -h " + DB_HOST + " -u " + DB_USER + " -p" + shlex.quote(DB_USER_PASSWORD)+ "; " + "use " + DB_TARGET + "; SET autocommit=0; SET unique_checks=0; SET FOREIGN_KEY_CHECKS=0; " + "source" + os.getcwd() + "\AllPrintings.sql; SET autocommit=1; SET unique_checks=1; SET FOREIGN_KEY_CHECKS=1;"
    print(importdb)
    #os.system(importdb)
    
    

    输出:

    mysql -h 1.1.1.1 -u root -ppassword; use somedb; SET autocommit=0; SET unique_checks=0; SET FOREIGN_KEY_CHECKS=0; source/some/pathAllPrintings.sql; SET autocommit=1; SET unique_checks=1; SET FOREIGN_KEY_CHECKS=1;
    

    从输出:

    1. 第一个 ;mysql -h 1.1.1.1 -u root -ppassword; 使控件进入 MySQL 客户端 shell,您不再使用 python 来回答您的以下查询。

      但它似乎在 first 之后停止执行它们;

      1. 如果您检查输出 source/some/pathAllPrintings.sql; - 源和文件名之间应该有空格。

      2. SET 命令必须存在于您的 AllPrintings.sql 文件中,如下所示:

      # <AllPrintings.sql - start of file>
      
      SET autocommit=0;
      SET unique_checks=0;
      SET foreign_key_checks=0;
      
      # <your_queries in the sql file>
      
      COMMIT;
      SET unique_checks=1;
      SET foreign_key_checks=1;
      
      # <AllPrintings.sql - end of file>
      
      

      解决方案:

      如第 3 点所述,在 AllPrintings.sql 文件本身中添加 SET 命令,并如下更改 importdb 变量

      importdb = "mysql -h " + DB_HOST + " -u " + DB_USER + " -p" + shlex.quote(DB_USER_PASSWORD)+ " -D " + DB_TARGET + " < " + os.getcwd() + "\AllPrintings.sql"
      

      那应该适合你。

    【讨论】:

    • 谢谢你!修改数据库将导入时间从 73 分钟减少到 2 分钟。我将使用最终代码编辑我的问题。为了进一步传播业力,您可以向我发送任何慈善机构的链接,我将代表您捐赠 10 欧元 ;-)
    猜你喜欢
    • 2012-02-13
    • 2012-11-11
    • 1970-01-01
    • 1970-01-01
    • 2010-11-20
    • 2013-09-03
    • 2013-01-13
    相关资源
    最近更新 更多