【问题标题】:MySQL Optimize UNION queryMySQL 优化 UNION 查询
【发布时间】:2012-12-18 07:16:25
【问题描述】:

我正在尝试优化查询。

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

所以我们开始:

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

  • md5 (varchar)
  • 值(varchar)。
  • 上次更新(日期时间)

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

搜索应返回最多一条与 10 个 md5 键之一匹配的记录。键具有优先级。因此,如果存在优先级 1 的记录,它将优先于优先级 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 实现吗?

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

【问题讨论】:

  • Union ALL 不使用索引所以我认为你不能优化太多。
  • 优先级如何确定?
  • 查尔斯 - 谢谢。目前,优先级由应用程序本身定义。理论上它是动态的,但实际上它“或多或少”是静态的,因此它可以进入数据库(实际上请参见下面的我的一个 cmets)。我会尝试将prio放入数据库并使用index+limit+order by

标签: mysql sql optimization union explain


【解决方案1】:

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

不幸的是,当有重复的 lastupdated 值时,Gavin 引用的分组最大值将产生多行(诚然,在您的情况下可能不是问题)。

实际上,有一种 MySQL 方法可以得到这个答案,使用 group_concatsubstring_index

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

【讨论】:

  • 戈登 - 谢谢。但是 UNION 中的每个选择仍然会单独执行,对吗?这就是我要避免的,但似乎 UNION 不能受到这种影响。
  • @user1946784 。 . .在第一个带有索引的示例中,每个选择都是单独完成的,但效率很高。该表没有被读取;索引和关联页面中只有一条记录。在第二个示例中,mytable 要么被扫描,要么需要md5 上的索引。
【解决方案2】:

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 上的复合索引是否会有所帮助;你需要尝试一下。

【讨论】:

  • Ollie - 谢谢 - 实际上设计是优先级可能在运行时发生变化,这就是在查询中提供它们的原因。
  • 奥利 - 也许你是对的。这些表可能会被重组,以便我们在数据库中的某个位置拥有索引的优先级,并且应用程序可以只使用具有限制 + 顺序的索引,而无需任何 UNION 魔法。我们明天见……
【解决方案3】:

有一种更好的方法来做到这一点,它不需要 UNION。您真的想要每个键的分组最大值,并具有自定义排序。

Groupwise Max

Order by FIELD()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-04
    • 2019-06-09
    • 2017-12-06
    • 2013-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多