MySQL优化UNION查询

时间:2013-01-03 21:01:06

标签: mysql sql optimization union explain

我正在尝试优化查询。

我的问题似乎与MySQL, Union ALL and LIMIT类似,答案可能相同(我害怕)。但是在我的情况下,有一个更严格的限制(1)以及日期时间列的索引。

所以我们走了:

为简单起见,我们只有一个包含三个的表:列:

  • md5(varchar)
  • value(varchar)。
  • lastupdated(datetime)

有一个索引(md5,已更新),因此选择md5键,按更新排序并限制为1将进行优化。

搜索应返回最多一条匹配10 md5键之一的记录。密钥具有优先权。因此,如果有prio 1的记录,它将优先于prio 2,3等的任何记录。

目前使用UNION ALL:

select * from

(

(
select 0 prio, value
from mytable
where md5 = '7b76e7c87e1e697d08300fd9058ed1db'
order by lastupdated desc 
limit 1
)

union all

(
select 1 prio, value
from mytable
where md5 = 'eb36cd1c563ffedc6adaf8b74c259723'
order by lastupdated desc 
limit 1
)

) x

order by prio
limit 1;

它可以工作,但是如果提供了10个密钥,UNION似乎会执行所有10个查询。

但是,从业务角度来看,可以顺序运行选择并在第一场比赛后停止。

这可能是普通的SQL吗?

或者唯一的选择是存储过程吗?

3 个答案:

答案 0 :(得分:0)

有一种更好的方法可以做到这一点,不需要UNION。你真的想要每个键的groupwise max,并自定义排序。

Groupwise Max

Order by FIELD()

答案 1 :(得分:0)

UNION ALL的优化器无法确定您的最新动态。

我不知道你是否可以这样做,但是假设你有一个md5prio表,其中包含你知道你正在寻找的哈希码列表。例如。

prio   md5
0      '7b76e7c87e1e697d08300fd9058ed1db'
1      'eb36cd1c563ffedc6adaf8b74c259723'
etc

在其中。

然后您的查询可能是:

    select mytable.*
      from mytable
      join md5prio on mytable.md5 = md5prio.md5
  order by md5prio.prio, mytable.lastupdated desc
     limit 1

这可能会保存重复的查询。你肯定需要mytable.md5上的索引。我不确定你在lastupdated上的复合指数是否有帮助;你需要尝试一下。

答案 2 :(得分:0)

在您的情况下,最有效的解决方案可能是在(md5, lastupdated)上构建索引。此索引应该用于非常有效地解析每个子查询(查找索引中的值,然后查找一个数据页)。

不幸的是,当存在重复的lastupdated值时,Gavin引用的groupwise max将产生多行(诚然,在您的情况下可能不是一个问题)。

实际上,有一种使用group_concatsubstring_index获得此答案的MySQL方式:

select p.prio,
       substring_index(group_concat(mt.value order by mt.lastupdated desc), ',', 1)
from mytable mt join
     (select 0 as prio, '7b76e7c87e1e697d08300fd9058ed1db' as md5 union all
      select 1 as prio, 'eb36cd1c563ffedc6adaf8b74c259723' as md5 union all
      . . .
     ) p
     on mt.md5 = p.md5