MySQL:合并几个大表并相加,优化

MySQL: merge several large tables and add values, optimization

我有几个大的 tables,字段如下:

+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
| fid1  | varchar(10) | NO   | MUL | NULL    |       |
| fid2  | varchar(10) | NO   |     | NULL    |       |
| cnt   | int(11)     | NO   |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

我在 {fid1,fid2,cnt} 上有索引,每个 table 有超过 20000000 行。

我想将这些 table 合并为一个,如果 fid1fid2 都匹配,那么新的 cnt 值将是这些 table 中 cnt 的总和。

我尝试了merge and add values from two tables中建议的方法,得到了类似

的结果
SELECT COALESCE(A.fid1, B.fid1) AS fid1, COALESCE(A.fid2, B.fid2) AS fid2, (COALESCE(A.cnt,0)+COALESCE(B.cnt,0))
FROM test1 A LEFT JOIN test2 B ON a.fid1 = b.fid1 AND A.fid2 = B.fid2
UNION
SELECT COALESCE(A.fid1, B.fid1) AS fid1, COALESCE(A.fid2, B.fid2) AS fid2, (COALESCE(A.cnt,0)+COALESCE(B.cnt,0))
FROM test1 A RIGHT JOIN test2 B ON a.fid1 = b.fid1 AND A.fid2 = B.fid2

但是,由于我有好几个table,而且都很大,所以用UNION的这个方法非常耗时。有没有其他方法可以有效地实现它或优化它?

谢谢!

无法在多个 table 上加速 UNION,因为 UNION 只是一个串联,在您的用例中,您必须读取所有 table 中的所有行。因此,如果你有 20 个 table 和每个单独的 select,那不会比一个联合快(给定相同的过滤器)

如果你想合并几百万行,它所花费的时间取决于 select-s 和写入,写入总是比较慢,所以:

  1. 创建 table new_table...并且不要添加密钥,那些现在只会减慢写入速度
  2. 不要使用任何多次触及一条记录的技巧,最好在内存中求和,然后写一次
  3. 使用 INSERT INTO new_table SELECT ... 因为它是在本地写入大量数据的最快方式 select(它将所有内容保存在服务器内存中,没有网络感动:) )
  4. 不要使用 LEFT 和 RIGHT 连接,使用外部连接
  5. 使用一些脚本或代码将连接生成一个长查询:

    INSERT INTO new_table
    SELECT fid1,fid2, sum(cnt) as cnt FROM
    (
    SELECT fid1, fid2, cnt FROM table1
    UNION ALL
    SELECT fid1, fid2, cnt FROM table2
    UNION ALL
    SELECT fid1, fid2, cnt FROM table3
    UNION ALL
    SELECT fid1, fid2, cnt FROM table4
    UNION ALL
    SELECT fid1, fid2, cnt FROM table5
    UNION ALL
    SELECT fid1, fid2, cnt FROM table6
    ) GROUP BY fid1, fid2;
    

    如果你 运行 缓冲不足,你可能会考虑不一次做所有事情,但总结 table1,2,3,4,5,6,7,8,9 ,10 到 sum1,table 11,12,13,14,15,16,17,18,19,20 到 sum2,最后求和。这意味着更多的工作、更多的分配存储 space 和更多的磁盘 io,但峰值缓冲区使用率较低。

    最后:您可以添加(或启用)所需的密钥。

    提示:

    • 在这种特殊情况下,如果您不经常更新 tables
    • ,使用 myisam 可能会获得更快的结果
    • 如果您使用大型数据集,您的数据库服务器内存是性能的关键参数(ssd 是第二个:)),因此您应该花时间调整缓冲区大小的配置。您可能需要 8 个小时的调整时间,但您可能会赢得 40 个小时的 运行 时间,而且每次必须重复此操作也需要 40 个小时。
    • 如果您不知道在 mysql.cnf 中设置什么,至少看看 Percona 的配置向导,https://tools.percona.com/,这是一个不错的开始。

更新:更正了用户 seahawk 指出的 UNION ALL

我没有关于您的方案的很多细节 - 但我假设这是非生产数据库,并且数据库负载无关紧要(因为无论如何您都在进行大量联合)。还假设您想要 MySQl 解决方案。

试试这个:

将您的所有数据插入 1 个巨人 table。 在其上添加复合索引(fld1,fld2)。 然后运行一组by查询 SELECT SUM(cnt), fld1, fld2 FROM table_name GROUP BY fld1,fld2;

联盟需要多长时间?那将是最坏的情况。并让我们知道您的最终解决方案需要多长时间。

祝你好运!

它可以通过非常有效和简单的方式实现。

第 1 步:

Alter table test1 
  add constraint fid1_fid2_unique UNIQUE (fid1,fid2);

第 2 步:

insert into test1 
   select  test2.fid1,test2.fid2,test2.cnt  from test2
 on duplicate key update test1.cnt=test1.cnt+test2.cnt ;

同样可以处理多个表。

您可以在下方验证结果link: http://sqlfiddle.com/#!9/07c6b/1