每组查询的通用最大N太慢

时间:2015-03-11 15:42:09

标签: mysql query-optimization greatest-n-per-group

以下查询需要18分钟才能完成。如何优化它以更快地执行?

基本上,我对每个公民的查询都来自citizens_staticcitizens_dynamic列最高的update_id_to列。

INSERT INTO latest_tmp (...)

SELECT cs1.*, cd1.*
FROM citizens c

JOIN citizens_static  cs1 ON c.id = cs1.citizen_id
JOIN citizens_dynamic cd1 ON c.id = cd1.citizen_id

JOIN (
    SELECT citizen_id, MAX(update_id_to) AS update_id_to
    FROM citizens_static
    GROUP BY citizen_id
) AS cs2 ON c.id = cs2.citizen_id AND cs1.update_id_to = cs2.update_id_to

JOIN (
    SELECT citizen_id, MAX(update_id_to) AS update_id_to
    FROM citizens_dynamic
    GROUP BY citizen_id
) cd2 ON c.id = cd2.citizen_id AND cd1.update_id_to = cd2.update_id_to;

latest_tmp表是MyISAM表,在导入期间禁用了索引。禁用它们可将执行时间从20分钟提高到18分钟,因此这不是最大的问题。

我还使用LEFT JOINWHERE t2.column IS NULL方法进行了基准测试。与我正在使用的INNER JOIN方法相比,它需要几个小时。

解释下面的查询输出。它似乎是使用索引。 explain

citizens_dynamiccitizens_staticcitizen_id,update_id_to上拥有主键,在update_id_to,citizen_id列上拥有名为“id”的辅助键。

2 个答案:

答案 0 :(得分:1)

你能用英语解释一下你想要的吗?

然后查看Groupwise Max并根据需要修改以下内容:

SELECT
        province, n, city, population
    FROM
      ( SELECT  @prev := '', @n := 0 ) init
    JOIN
      ( SELECT  @n := if(province != @prev, 1, @n + 1) AS n,
                @prev := province,
                province, city, population
            FROM  Canada
            ORDER BY
                province,
                population DESC
      ) x
    WHERE  n <= 3
    ORDER BY  province, n;

无论内部ORDER BY上的ASC / DESC如何,都会有一个全表扫描和一个&#39; filesort&#39;。

答案 1 :(得分:0)

我对MySQL不够熟悉,无法预测这种情况会不会更好,但我建议尝试一下:

SELECT cs1.*, cd1.*
FROM citizens c

JOIN citizens_static  cs1 ON c.id = cs1.citizen_id
AND NOT EXISTS ( SELECT *
                   FROM citizens_static cs2
                  WHERE cs2.citizen_id = cs1.citizen_id
                    AND cs2.update_id > cs1.update_id )

JOIN citizens_dynamic cd1 ON c.id = cd1.citizen_id
AND NOT EXISTS ( SELECT *
                   FROM citizens_dynamic cd2
                  WHERE cd2.citizen_id = cd1.citizen_id
                    AND cd2.update_id > cd1.update_id )

PS:请评论一下运行时间(如果它在一小时内返回=),那么我可能会学习(不)再次提出这种结构。