MySQL通过优化自行加入订单

时间:2012-03-27 15:22:08

标签: mysql optimization sql-order-by self-join

我有这样的疑问:

SELECT va.value, vc.value
FROM votingapi_cache va
LEFT JOIN votingapi_cache vc ON vc.content_id = va.content_id
WHERE va.content_type = 'node' AND va.value_type = 'percent' AND va.tag = 'vote' AND va.function = 'average' AND vc.content_type = 'node' AND vc.tag = 'vote' AND vc.function = 'count'
ORDER BY va.value DESC, vc.value DESC LIMIT 0, 10

EXPLAIN告诉我这个查询使用临时和filesort。它在桌面上运行近10秒,行数为500k。如何优化?

架构:

enter image description here

索引:

enter image description here

根据Joachim Isaksson提供的建议,没有性能改进,EXPLAIN:

enter image description here

2 个答案:

答案 0 :(得分:2)

我的建议是将联接分成两个查询......

首先,在列function, value上构建索引,

您的第一个查询应该是获得最佳平均值,
因为这是第一个排序值,
如:

SELECT average.value, average.content_id
FROM votingapi_cache average
WHERE average.function = 'average' /* plus other filter *
ORDER BY average.value DESC LIMIT 0, 30;

然后,循环到30行以获取content_id,
并且您的第二个第二个查询是获取每个content_id的30行计数,
这意味着:

select count.value, count.content_id
FROM votingapi_cache `count`
WHERE `count`.function = 'count'
and content_id in(...30 content_id);

循环通过第二个结果并与第一个结果结合以获得最佳10个平均值+计数desc

这可以避免大规模加入

答案 1 :(得分:0)

基于@ ajreal的答案,你可以像 -

那样做
SELECT averages.value, counts.value
FROM (
    SELECT *
    FROM votingapi_cache
    WHERE function = 'average'
    AND content_type = 'node'
    AND tag = 'vote'
    AND value_type = 'percent'
    ORDER BY value DESC
    LIMIT 0, 30
) AS averages
LEFT JOIN votingapi_cache counts
    ON averages.content_id = counts.content_id
    AND averages.content_type = counts.content_type
    AND averages.value_type = counts.value_type
    AND averages.tag = counts.tag
WHERE counts.function = 'count'
ORDER BY averages.value DESC, counts.value DESC
LIMIT 0, 10;