【问题标题】:MySQL INSERT INTO ... SELECT ... GROUP BY is too slowMySQL INSERT INTO ... SELECT ... GROUP BY 太慢了
【发布时间】:2013-03-04 19:44:05
【问题描述】:

我有一个大约 50M 行和格式的表格:

CREATE TABLE `big_table` (
  `id` BIGINT NOT NULL,
  `t1` DATETIME NOT NULL,
  `a` BIGINT NOT NULL,
  `type` VARCHAR(10) NOT NULL,
  `b` BIGINT NOT NULL,
  `is_c` BOOLEAN NOT NULL,
  PRIMARY KEY (`id`),
  INDEX `a_b_index` (a,b)
) ENGINE=InnoDB;

然后我定义表t2,没有索引:

Create table `t2` (
  `id` BIGINT NOT NULL,
  `a` BIGINT NOT NULL,
  `b` BIGINT NOT NULL,
  `t1min` DATETIME NOT NULL
 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

然后我使用来自big_table 的查询填充t2(这将添加大约 12M 行)。

insert into opportunities
  (id, a,b,t1min)
  SELECT id,a,b,min(t1)
    FROM big_table use index (a_b_index)
    where type='SUBMIT' and is_c=1
   GROUP BY a,b;

我发现处理 big_table 中的 5000 个不同的 (a,b) 大约需要一分钟。
由于big_table 中有 12M 个不同的(a,b),因此运行大约需要 40 小时 对所有big_table 的查询。

出了什么问题?

如果我只做SELECT ...,那么查询会在大约 2 秒内完成 5000 行。如果我SELECT ... INTO OUTFILE ...,那么对于 5000 行,查询仍然需要 60 秒。

EXPLAIN SELECT ... 给出:

id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
1,SIMPLE,stdnt_intctn_t,index,NULL,a_b_index,16,NULL,46214255,"Using where"

【问题讨论】:

  • q1:只选择选择需要多长时间?
  • q2:select部分的解释计划是什么?
  • EXPLAIN SELECT ...
  • 在上面添加了EXPLAIN SELECT ...SELECT ... 结果。
  • 您可能会受益于 1/ 删除索引提示,以及 2/ 在 type 和 is_c 列上添加另一个索引(添加后检查解释计划并在表上执行分析表)

标签: mysql select sql-insert


【解决方案1】:

我发现问题在于GROUP_BY 导致对big_table 的随机访问读取过多。以下策略允许通过big_table 进行一次连续行程。首先,我们给t2添加一个key:

Create table `t2` (
  `id` BIGINT NOT NULL,
  `a` BIGINT NOT NULL,
  `b` BIGINT NOT NULL,
  `t1min` DATETIME NOT NULL,
  PRIMARY KEY (a,b),
  INDEX `id` (id)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

然后我们填写t2 使用:

insert into t2
  (id, a,b,t1min)
  SELECT id,a,b,t1
    FROM big_table
    where type='SUBMIT' and is_c=1
 ON DUPLICATE KEY UPDATE 
   t1min=if(t1<t1min,t1,t1min),
   id=if(t1<t1min,big_table.id,t2.id);

由此产生的加速是几个数量级。

【讨论】:

    【解决方案2】:

    group by 可能是问题的一部分。您正在 (a,b) 上使用索引,但未使用您的位置。我会有一个索引

    (类型,is_c,a,b)

    此外,您正在获取“ID”,但未指定哪个...您可能想要执行 MIN(ID) 以获得一致的结果。

    【讨论】:

    • 我在(type,is_c,a,b) 上尝试了索引,5000 行大约需要一个小时。我的猜测是索引不再适合 nnodb 缓冲池(我的机器上是 4GB)。
    • min(id) 的想法很有帮助。
    猜你喜欢
    • 1970-01-01
    • 2012-03-11
    • 2010-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-25
    • 1970-01-01
    • 2018-11-06
    相关资源
    最近更新 更多