如何避免使用临时表进行此简单查询

时间:2010-11-11 19:55:29

标签: mysql performance

如何避免为此查询使用临时表并仍然实现相同的目标?

EXPLAIN EXTENDED 
SELECT DISTINCT id, view_count
  FROM
      screenshot_udb_affect_assoc
  INNER JOIN
      screenshot ON id = screenshot_id
  WHERE unit_id = 110 LIMIT 0, 6

id  select_type table   type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  screenshot_udb_affect_assoc ref screenshot_id,unit_id   unit_id 4   const   34  100.00  Using temporary
1   SIMPLE  screenshot  eq_ref  PRIMARY PRIMARY 4   source_core.screenshot_udb_affect_assoc.screenshot...   1   100.00

我已将查询更新为不再使用RAND(),而LIMIT将通过PHP随机化。虽然它仍然显示它正在使用临时表

2 个答案:

答案 0 :(得分:2)

SELECT  rnd_id, rnd_value
FROM    (
        SELECT  @cnt := COUNT(*) + 1,
                @lim := 6
        FROM    screenshot
        JOIN    screenshot_udb_affect_assoc
        ON      screenshot_id = id
        WHERE   unit_id = 110
        ) vars
STRAIGHT_JOIN
        (
        SELECT  r.*,
                @lim := @lim - 1
        FROM    (
                SELECT  id, view_count
                FROM    screenshot
                JOIN    screenshot_udb_affect_assoc
                ON      screenshot_id = id
                WHERE   unit_id = 110
                ) r 
        WHERE   (@cnt := @cnt - 1)
                AND RAND() < @lim / @cnt
        ) i

在本文中更详细地解释:

这仍然需要对满足查询的所有行进行两次扫描,但不需要filesort

创建以下索引:

screenshot (unit_id)
screenshot_udb_affect_assoc (screenshot_id)

答案 1 :(得分:2)

ORDER BY RAND()会自动导致创建临时表。

它的工作原理是创建一个临时表,其中包含一个用随机数填充的新列。然后,它使用ORDER BY对临时表执行查询。

为避免使用临时表,您必须找到一种选择随机数的新方法。

我之前使用的解决方案(依赖于未删除的行)是在表上执行SELECT COUNT,然后在该范围内选择随机数并仅选择这些行。

还有许多其他解决方案,但ORDER BY RAND()不是一个好的解决方案。