Mysql 批量创建海量记录的最佳实践

Mysql 批量创建海量记录的最佳实践,mysql,django,performance,orm,Mysql,Django,Performance,Orm,我使用bulk\u create将一百万条记录插入到新表中。需要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):

我使用
bulk\u create
将一百万条记录插入到新表中。需要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)
我试过几种方法:

  • 使用合适的
    批量大小
    。对我来说,最好的价值大约是4000英镑。这需要80-90秒
  • 使用
    ThreadPool()
    。速度要慢得多,大约120-140秒
  • 删除
    日期字段
    上的索引。比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分钟。时间的增加不是线性的

    批量生产有什么问题吗


    更新1 虽然我已经接受了答案,但我认为我应该理解其中的奥秘。所以我做了更多的测试,发现Django的模型创建是速度减慢的根本原因。当我有800000条记录时,调用800000次创建模型将非常耗时

    ORM框架执行许多我们没有看到的内部工作,例如完整性检查。在我的例子中,大量记录将被导入到一个空的数据库表中,因此不需要进行检查

    现在我使用了
    cursor.executemany()
    ,它将800000条4列记录的插入时间从54秒缩短到16秒。并将80万条13列记录的插入时间从13分钟缩短到46秒


    根据我的实验,每3000-5000条记录,你就调用
    executemany
    。我在一次调用中尝试了800k条记录,这非常慢。

    虽然批量创建在处理HTML表单时可用于保存少量记录,但它并不适合保存数千条记录。正如您已经发现的,它的速度很慢,因为它需要大量内存,并向数据库发送非常大的查询。福图纳利前来救援

    LOAD DATA INFILE语句将文本文件中的行读取到 以非常高的速度移动桌子。加载数据填充是对 选择。。。进入外文件

    我们可以生成一个类似于使用文档中的以下示例生成的文件

    import csv
        with open('some.csv', 'wb') as f:
        writer = csv.writer(f)
        writer.writerows(someiterable)
    
    最后,正如您已经发现的,加载数据的本地选项。。有时可以用于方便

    仅当服务器和客户端都已安装时,本地才起作用 配置为允许它

    使用此选项时,不需要手动将文件传输到服务器。您可以在客户端生成CSV文件,本地选项将使mysql客户端自动将文件传输到服务器

    如果未指定LOCAL,则文件必须位于服务器主机上 并由服务器直接读取


    bulk create没有什么问题,但它的设计并不是要一次将数百万条记录加载到数据库中。对于一天结束时的这类任务,没有什么比在中使用加载数据更好的了FILE@e4c5我相信
    在本地文件中加载数据
    会更快。你想发布一个答案,这样我就可以接受了。非常感谢。抱歉耽搁了。实际上我已经忘记了本地选项,所以回答您的问题就像参加复习课程一样。
    key\u buffer\u size
    应该是可用RAM的10-20%。@RickJames谢谢您的提示。但我的案例似乎不会产生太多mysql数据(大约50MB)。真正的瓶颈是django的ORM。它为查询数据提供了便利,但对于构建海量对象来说,效率不高。最后,我找到了一个很好的解决方案。请参阅问题的“更新1”部分