【发布时间】:2015-12-24 16:16:54
【问题描述】:
我使用bulk_create 将 1 条 mio 记录插入到新表中。这需要 80 秒。 Django 只使用一个 CPU 内核(大约 25% CPU,但没有一个内核达到 100%)我相信有改进的潜力。
这里是代码
class Stock(models.Model):
code = models.CharField(max_length=6, unique=True)
name = models.CharField(max_length=8)
class Watchers(models.Model):
date = models.DateField(db_index=True)
stock = models.ForeignKey(Stock, unique_for_date="date")
num = models.PositiveIntegerField(default=0)
batch = []
for input in inputs:
watcher = Watcher(date=input['date'], stock=get_stock(), num=input['num'])
batch.append(watcher)
Watcher.objects.bulk_create(batch)
我已经尝试了几件事:
- 使用正确的
batch_size。对我来说最好的值大约是 4000。这需要 80-90 秒。 - 使用
ThreadPool()。它要慢得多,大约 120-140 秒 - 删除
DateField上的索引。比 1 慢一点。
我正在使用 MySQL 5.6 社区版。存储引擎是 MyISAM。这是配置。
[mysqld]
server-id = 1
default-storage-engine = MyISAM
port = 3306
socket = /tmp/mysql.sock
datadir = "{MYSQLDATAPATH}"
skip-external-locking
explicit_defaults_for_timestamp = TRUE
# MyISAM #
key-buffer-size = 32M
max_allowed_packet = 16M
# CACHES AND LIMITS #
tmp-table-size = 32M
max-heap-table-size = 32M
query-cache-type = 0
query-cache-size = 0
max-connections = 500
thread-cache-size = 50
open-files-limit = 65535
table-definition-cache = 1024
table-open-cache = 2048
# LOGGING
log-bin = mysql-bin
binlog_format = mixed
当我导入另一个表(结构相似,索引相同,但有 9 列)时,需要 15 分钟。时间增加不是线性的。
bulk_create 有什么问题吗?
更新 1
虽然我已经接受了答案,但我想我应该明白其中的奥秘。于是又做了一些测试,发现Django的模型创建速度变慢的根本原因。当我有 800000 条记录时,调用 800000 次创建模型将非常耗时。
ORM 框架做了很多我们看不到的内部工作,例如完整性检查。在我的例子中,大量的记录会被导入到一个空的数据库表中,所以检查是没有必要的。
现在我使用cursor.executemany(),它将800000条4列记录的插入时间从54秒缩短到16秒。并将800000条13列记录的插入时间从13分钟缩短到46秒。
根据我的实验,您会为每 3000-5000 条记录调用 executemany。我试过一次调用 80 万条记录,这非常慢。
【问题讨论】:
-
批量创建没有问题,但它并不是真正设计为一次将数百万条记录加载到数据库中。对于一天结束时的那种任务,没有什么比使用 LOAD DATA IN FILE 更好
-
@e4c5 我相信
LOAD DATA IN LOCAL FILE会更快。您要发布答案以便我接受吗? -
非常感谢。抱歉耽搁了。实际上,我已经完全忘记了 LOCAL 选项,所以回答您的问题就像参加进修课程。
-
key_buffer_size应该是 可用 RAM 的 10-20%。 -
@RickJames 感谢您的提示。但似乎我的案例并没有产生太多的 mysql 数据(大约 50MB)。真正的瓶颈是 django 的 ORM。它为查询数据提供了便利,但构造海量对象,效率不高。
标签: mysql django performance orm