sta*_*005 6 mysql django performance orm
我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)
Run Code Online (Sandbox Code Playgroud)
我尝试了几件事:
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
Run Code Online (Sandbox Code Playgroud)
当我导入另一个表(类似的结构,相同的索引,但有9列),它需要15分钟.时间增加不是线性的.
bulk_create有什么问题吗?
虽然我接受了答案,但我想我应该理解这个谜.所以我做了一些测试,发现Django的模型创建是减速的根本原因.当我有800000条记录时,调用800000次创建模型将非常耗时.
ORM框架执行许多我们没有看到的内部工作,例如完整性检查.在我的例子中,大量记录将被导入到空数据库表中,因此不需要检查.
现在我使用cursor.executemany(),它将800000 4列记录的插入时间从54秒缩短到16秒.并将800000个13列记录的插入时间从13分钟缩短到46秒.
根据我的实验,你需要executemany每3000-5000条记录.我在一次通话中尝试了800k记录,这非常慢.
虽然bulk_create 对于在处理HTML 表单时保存少量记录很有用,但它并不适合保存数千条记录。正如您已经发现的那样,它很慢,因为它需要大量内存并向数据库发送非常大的查询。Fortunatley LOAD DATA IN FILE来救援。
LOAD DATA INFILE 语句以非常高的速度将文本文件中的行读取到表中。LOAD DATA INFILE 是 SELECT ... INTO OUTFILE 的补充。
我们可以生成一个类似于使用csv writer生成的文件,以下示例来自文档。
import csv
with open('some.csv', 'wb') as f:
writer = csv.writer(f)
writer.writerows(someiterable)
Run Code Online (Sandbox Code Playgroud)
最后,正如您已经发现的那样,有时可以使用 LOAD DATA .. 的 LOCAL 选项以方便起见。
LOCAL 仅在您的服务器和客户端都已配置为允许时才有效
使用此选项时,不需要手动将文件传输到服务器。您可以在客户端生成 CSV 文件,本地选项将导致 mysql 客户端自动将文件传输到服务器。
如果未指定 LOCAL,则该文件必须位于服务器主机上并由服务器直接读取。