【问题标题】:Export/import 50-million row database without the index?在没有索引的情况下导出/导入 5000 万行数据库?
【发布时间】:2014-01-17 07:14:24
【问题描述】:

我有很多数据 - 5000 万行。但由于次优选择,我选择了错误的索引,现在插入需要很长时间(插入 1000 行需要 60 秒)。

CREATE TABLE `slots` (
 `customerid` int(11) NOT NULL,
 `orderid` int(11) NOT NULL,
 `queueid` int(11) NOT NULL AUTO_INCREMENT,
 `item_id` int(3) NOT NULL,
 `variable1` int(3) NOT NULL,
 `variable2` int(3) NOT NULL,
 `variable3` int(3) NOT NULL,
 `variable4` int(3) NOT NULL,
 `variable5` int(3) NOT NULL,
 `variable6` int(3) NOT NULL,
 `variable7` tinyint(1) NOT NULL,
 `variable8` tinyint(1) NOT NULL,
 `variable9` tinyint(1) NOT NULL,
 PRIMARY KEY (`customerid`,`orderid`,`queueid`),
 UNIQUE KEY `queueid` (`queueid`),
 KEY `orderid` (`orderid`)
) ENGINE=InnoDB AUTO_INCREMENT=25883472 DEFAULT CHARSET=latin1

我认为这是因为 PRIMARY KEY 是多列的,并且每次插入后都需要重新索引表(因为 customeridorderid 没有以任何升序/降序方式插入,而是在随机位置插入)。如果我在queueid 上有一个自动增量的主键,它会大大加快插入速度吗?

我可以在没有损坏索引的情况下导出表吗?然后用更好的键重新索引它?

我尝试使用 SQL 语句删除键,但花了很长时间,我中断了它。有什么方法可以看到进度吗?如果我不知道我需要多长时间,我不会等待 - 毕竟可能需要几天?

我需要重新索引这个表,因为它最终将有 10 亿行,并且插入性能会更加恶化。

或者也许最好放弃我已经插入的内容并使用适当的索引开始一个新表?并且不用费心重用旧数据?

【问题讨论】:

  • 显示您的插入查询。和最后尝试的代码
  • 现在插入 PHP 脚本的工作方式如下:获取数据。创建 500-1000 行 INSERT IGNORE 语句(将它们插入到一个“go”中,而不是通过 500-1000 个单独的 INSERT 操作)。执行 INSERT IGNORE 查询。
  • 还有几件事要尝试:(1) 使用多行插入添加数据,(2) 在事务中将多个插入一起批处理(例如 1000 个),(3) 以上两者一起。这可能会为您带来一些性能改进。

标签: php mysql sql phpmyadmin innodb


【解决方案1】:

您可以使用禁用键选项导出表格。

参考这个链接 https://dba.stackexchange.com/questions/3069/does-mysqldump-export-indices-by-default

【讨论】:

    【解决方案2】:

    最大的问题是,这张桌子将用于什么?如果唯一的查询将是 ORDER_ID 的范围或 ITEM_ID 上的聚合,那么您只需要这些列上的单独索引。将 QUEUE_ID 设为主键(因为自动增量确保唯一且无论如何都不为空)。请尝试以下操作:

    更新:根据下面 OP 的评论,每个客户可以有多个订单 ID,反之亦然,但组合必须是唯一的。 IMO,更容易创建满足唯一约束的卫星表,并在此 slots 表中使用该表的索引。

    CREATE TABLE cust_order (
        combo_id int(11) NOT NULL AUTO_INCREMENT,
        customerid int(11) NOT NULL,
        orderid int(11) NOT NULL,
        PRIMARY KEY combo_id,
        INDEX customerid (customerid),
        INDEX orderid (orderid),
        UNIQUE KEY combination (customerid, orderid)
    ) ENGINE=INNODB;
    
    CREATE TABLE `slots` (
     `combo_id` int(11) NOT NULL,
     `queueid` int(11) NOT NULL AUTO_INCREMENT,
     `item_id` int(3) NOT NULL,
     `variable1` int(3) NOT NULL,
     ...
     ...
     `variable9` tinyint(1) NOT NULL,
     PRIMARY KEY `queueid`,
     INDEX `combo_id` (`combo_id`),
     INDEX `itemid` (`itemid`),
     FOREIGN KEY (combo_id)
       REFERENCES cust_order (combo_id)
    ) ENGINE=INNODB;
    

    您必须运行两个不同的插入查询。首先,您加载组合表,它只处理没有卫星数据的数字索引,它应该非常快。之后,当您插入slots 时,通过customerid + orderid 查找将非常快,您只需使用combo_id 作为外键。

    请注意,您必须使用 InnoDB 引擎才能使外键工作。

    【讨论】:

    • 我需要确保 customerid 和 orderid 都是唯一的(一个 orderid 可以有多个客户,反之亦然)自动增量的高价值是我少数导入的残余 - 我认为这是它来自哪里。
    • 嗯,有什么效果吗?请标记任何正确的答案或发布您自己的答案。
    • 我不得不删除所有数据并重建结构。我会尽快发布我的解决方案 - 一旦我完成设置。感谢您的帮助。
    【解决方案3】:

    在 phpMyAdmin 中,首先使用操作复制您的表,但选择“仅结构”。然后在您复制的表中,更改结构(删除不需要的索引)。然后从您的原始表中,使用操作,将其复制到您复制的表中,并使用“仅数据”。

    如果最后的复制操作给您带来麻烦,请仅从原始表中导出数据(从“自定义”面板将其导入到您复制的表中。

    【讨论】:

      猜你喜欢
      • 2019-05-03
      • 1970-01-01
      • 2015-11-27
      • 1970-01-01
      • 2011-06-19
      • 2018-01-13
      • 1970-01-01
      • 2017-04-29
      • 1970-01-01
      相关资源
      最近更新 更多