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

时间:2015-08-26 18:42:51

标签: mysql optimization merge union

我有几个包含以下字段的大表:

+-------+-------------+------+-----+---------+-------+
| 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}上有索引,每个表的行数超过20000000

我希望将这些表合并为一个,如果fid1fid2都匹配,那么新的cnt值将是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

但是,由于我有几个表并且它们都非常大,因此使用UNION的此方法非常耗时。有没有其他方法可以有效地实施它或以任何方式优化它?

谢谢!

1 个答案:

答案 0 :(得分:1)

无法在多个表上加速UNION,因为UNION只是一个连接,在您的用例中,您必须读取所有表中的所有行。因此,如果您有20个表,并从每个表中选择,那将不会比一个联合更快(给定相同的过滤器)

如果您想要合并数百万行,则所需的时间取决于select-s和写入,并且写入总是较慢,因此:

  1. 创建表new_table ....并且不要添加密钥,这些只会减慢写入速度
  2. 不要使用任何不止一次触及一条记录的技巧,最好在内存中加总,然后再写一次
  3. 使用INSERT INTO new_table 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,表11,12,13 ,14,15,16,17,18,19,20为sum2,并在末尾求和。这意味着更多的工作,更多的分配存储空间,以及更多的磁盘io,但峰值缓冲区的使用率更低。

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

    提示:

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