加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

mysql – 大量记录的bulk_create的最佳实践

发布时间:2020-12-11 23:51:51 所属栏目:MySql教程 来源:网络整理
导读:我使用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(

我使用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.我在一次通话中尝试了800k记录,这非常慢.

最佳答案 虽然bulk_create对于在处理HTML表单时保存少量记录很有用,但它并不适合保存数千条记录.正如您已经发现的那样,它很慢,因为它需要大量内存并向数据库发送一个非常大的查询. Fortunatley LOAD DATA IN FILE来救援.

The LOAD DATA INFILE statement reads rows from a text file into a
table at a very high speed. LOAD DATA INFILE is the complement of
SELECT … INTO OUTFILE.

我们可以生成类似于使用csv writer生成的文件,以下示例来自文档.

import csv
    with open('some.csv','wb') as f:
    writer = csv.writer(f)
    writer.writerows(someiterable)

最后,正如您已经发现的那样,有时可以使用LOAD DATA …的LOCAL选项.

LOCAL works only if your server and your client both have been
configured to permit it

使用此选项时,无需手动将文件传输到服务器.您可以在客户端生成CSV文件,local选项将使mysql客户端自动将文件传输到服务器.

If LOCAL is not specified,the file must be located on the server host
and is read directly by the server.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读