0

我知道这一定是一个相当普遍的问题,我确信答案很容易获得,但我不知道如何表达我的搜索,所以我不得不在很大程度上自己解决这个问题。

表 A

id | content_id | score
1  | 2          | 16
2  | 2          | 4
3  | 3          | 8
4  | 3          | 12

表 B

id | content
1  | "Content Goes Here"
2  | "Content Goes Here"
3  | "Content Goes Here"

目标:对表 A 中的所有分数求和,按唯一的 content_id 分组,并显示与 id 关联的内容,按总分排序。

当前工作查询:

SELECT a.content_id, b.content, SUM(a.score) AS sum 
FROM table_a a 
LEFT JOIN table_b b ON a.content_id = b.id 
GROUP BY a.content_id 
ORDER BY sum ASC;

问题:据我所知,按照我构建查询的方式,通过遍历 table_a 上的每条记录、检查 table_b 中具有相同 ID 的记录并获取内容字段,从 table_b 中获取内容。这里的问题是table_a 中有近500k+ 条记录,而table_b 中有112 条记录。这意味着可能会执行 500,000 x 112 交叉表查找/匹配,仅将 112 个唯一内容字段附加到最终结果集中的总共 112 个结果中。

帮助!:如何更有效地将 table_b 中的 112 个内容字段附加到查询产生的 112 个结果中?我猜它与查询执行顺序有关,比如在生成总和之后以某种方式仅查找内容字段并将其附加到匹配的结果行​​并将其缩小到只有 112 条记录?研究过 MySQL API 并对各种子查询、几个连接进行了基准测试,甚至尝试过使用 UNION。这对你们来说可能是非常明显的事情,但我的大脑就是无法绕过它。

仅供参考:如前所述,查询确实有效。结果在大约 8 到 10 秒内产生,当然,由于查询缓存,之后的每个后续查询都是立即的。但对我来说,这很简单,我知道 8 秒至少可以缩短一半。我只是在我的内心深处感觉到它。就在我的胆量深处。

我希望这足够简洁,如果我需要澄清或解释更好的东西,请告诉我!提前致谢。

4

2 回答 2

2

MySQL 查询优化器只允许“嵌套循环连接”** 这些是用于评估 INNER 连接的内部运算符。其他 RDBMS 允许更有效的其他类型的 JOIN。

但是,在您的情况下,您可以试试这个。希望优化器在 JOIN之前进行聚合

SELECT
    a.content_id, b.content a.sum
FROM
    (
    SELECT content_id, SUM(score) AS sum 
    FROM table_a
    GROUP BY content_id
    ) a 
    JOIN table_b b ON a.content_id = b.id 
ORDER BY
    sum ASC;

此外,如果您不希望结果排序,您可以使用ORDER BY NULL通常filesortEXPLAIN. 当然,我假设 2content_id列上有索引(一个主键,一个外键索引)

最后,我还假设一个 INNER JOIN 就足够了:每个都a.contentid存在于tableb. 如果没有,则您缺少外键和索引a.contentid

** 越来越好,但您需要 MariaDBMySQL 5.6

于 2013-06-28T06:42:23.247 回答
1

这应该快一点:

SELECT
    tmp.content_id,
    b.content,
    tmp.asum
FROM (
    SELECT 
        a.content_id, 
        SUM(a.score) AS asum 
    FROM 
        table_a a 
    GROUP BY 
        a.content_id 
    ORDER BY 
        NULL
) as tmp
LEFT JOIN table_b b 
    ON tmp.content_id = b.id 
ORDER BY
    tmp.asum ASC

当您想对它们进行基准测试时,您可以使用它EXPLAIN来检查这两个查询的查询执行计划

于 2013-06-28T06:43:48.517 回答