提高 Django 中的 INSERT 性能以处理大量大量数据的记录
Increasing INSERT Performance in Django For Many Records of HUGE Data
所以我已经尝试解决这个问题一段时间了,尽管在 Whosebug 和许多 Google 搜索。
所以基本上我需要通过 Django 将大量数据记录(约 200 万条)插入到我的 MySQL 数据库中,每个记录条目高达 180KB。我已将测试缩减到 2,000 个插入,但仍然无法将 运行 时间减少到合理的数量。 2,000 次插入目前大约需要 120 秒。
所以我尝试了以下所有方法(以及每种方法的许多组合)都无济于事:
- "Classic" Django ORM 创建模型和 .save()
- 单笔交易 (transaction.atomic())
- Bulk_create
- 原始 SQL 在 for 循环中插入
- 原始 SQL "executemany"(在一个查询中插入多个值)
- 设置 SQL 属性,如 "SET FOREIGN_KEY_CHECKS=0"
- SQL 开始...提交
- 将大量插入分成较小的批次
如果我忘了列出一些东西,我深表歉意,但此时我已经尝试了很多不同的东西,我什至无法跟踪啊。
非常感谢可能不得不使用 Django 数据库插入执行类似任务的人在提高性能方面的一点帮助。
如果我遗漏了任何必要的信息,请告诉我!
这确实超出了 django 的范围。 Django 只是将你的 python 翻译成 on INSERT INTO
语句。对于 django 层上的大多数性能,完全跳过它(通过 sql raw)可能是最好的,即使 python 处理与 sql 数据库的 IO 相比相当快。
您应该更关注数据库。我是 postgres 用户,所以我不知道 mysql 有哪些配置选项,但可能有一些可用的微调。
如果你这样做了,但仍然没有增加,你应该考虑使用 SSD,RAID 0 中的 SSD,甚至是内存中的数据库,以跳过 IO 时间。
分片也可能是一种解决方案 - 拆分任务并并行执行它们。
但是如果插入不是时间紧迫的,即可以随时完成,但不应阻止页面加载,我推荐 celery。
在那里,您可以将任务排队,以便在有时间时执行 - 异步。
您还可以尝试删除表上的任何索引(以及任何其他约束),然后在插入后重新创建索引和约束。
更新索引和检查约束会减慢每次插入的速度。
所以我发现编辑 mysql /etc/mysql/my.cnf 文件并配置一些 InnoDB 设置可以显着提高性能。
我设置:
- innodb_buffer_pool_size = 9000M 75% 的系统内存
- innodb_log_file_size = 2000M 以上数值的20%-30%
重新启动了 mysql 服务器,这将 50 次插入从约 3 秒减少到约 0.8 秒。还不错!
现在我注意到对于大数据量,插入时间逐渐变长。 50 次插入从大约 0.8 秒开始,但在 100 次左右的批次之后,平均时间达到 1.4 秒并继续增加。
如果解决了会反馈。
所以我已经尝试解决这个问题一段时间了,尽管在 Whosebug 和许多 Google 搜索。
所以基本上我需要通过 Django 将大量数据记录(约 200 万条)插入到我的 MySQL 数据库中,每个记录条目高达 180KB。我已将测试缩减到 2,000 个插入,但仍然无法将 运行 时间减少到合理的数量。 2,000 次插入目前大约需要 120 秒。
所以我尝试了以下所有方法(以及每种方法的许多组合)都无济于事:
- "Classic" Django ORM 创建模型和 .save()
- 单笔交易 (transaction.atomic())
- Bulk_create
- 原始 SQL 在 for 循环中插入
- 原始 SQL "executemany"(在一个查询中插入多个值)
- 设置 SQL 属性,如 "SET FOREIGN_KEY_CHECKS=0"
- SQL 开始...提交
- 将大量插入分成较小的批次
如果我忘了列出一些东西,我深表歉意,但此时我已经尝试了很多不同的东西,我什至无法跟踪啊。
非常感谢可能不得不使用 Django 数据库插入执行类似任务的人在提高性能方面的一点帮助。
如果我遗漏了任何必要的信息,请告诉我!
这确实超出了 django 的范围。 Django 只是将你的 python 翻译成 on INSERT INTO
语句。对于 django 层上的大多数性能,完全跳过它(通过 sql raw)可能是最好的,即使 python 处理与 sql 数据库的 IO 相比相当快。
您应该更关注数据库。我是 postgres 用户,所以我不知道 mysql 有哪些配置选项,但可能有一些可用的微调。
如果你这样做了,但仍然没有增加,你应该考虑使用 SSD,RAID 0 中的 SSD,甚至是内存中的数据库,以跳过 IO 时间。
分片也可能是一种解决方案 - 拆分任务并并行执行它们。
但是如果插入不是时间紧迫的,即可以随时完成,但不应阻止页面加载,我推荐 celery。 在那里,您可以将任务排队,以便在有时间时执行 - 异步。
您还可以尝试删除表上的任何索引(以及任何其他约束),然后在插入后重新创建索引和约束。
更新索引和检查约束会减慢每次插入的速度。
所以我发现编辑 mysql /etc/mysql/my.cnf 文件并配置一些 InnoDB 设置可以显着提高性能。
我设置:
- innodb_buffer_pool_size = 9000M 75% 的系统内存
- innodb_log_file_size = 2000M 以上数值的20%-30%
重新启动了 mysql 服务器,这将 50 次插入从约 3 秒减少到约 0.8 秒。还不错!
现在我注意到对于大数据量,插入时间逐渐变长。 50 次插入从大约 0.8 秒开始,但在 100 次左右的批次之后,平均时间达到 1.4 秒并继续增加。
如果解决了会反馈。