MySQL:在内部查询中使用“ORDER BY”优化 UNION

Luk*_*kas 11 mysql performance order-by subquery union query-performance

我刚刚建立了一个日志系统,它由多个具有相同布局的表组成。

每个数据源有一个表。

对于日志查看器,我想

  • UNION所有的日志表
  • 按帐户过滤它们
  • 添加一个伪列来识别来源,
  • 按时间排序
  • 限制它们进行分页

所有表都包含一个称为zeitpunkt索引日期/时间列的字段。

我的第一次尝试是:

(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
 'hp' AS source FROM is_log AS l WHERE l.account_id = 730)

UNION

(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
 'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730)

ORDER BY zeit DESC LIMIT 10;
Run Code Online (Sandbox Code Playgroud)

优化器无法使用此处的索引,因为来自两个表的所有行都由子查询返回并在UNION.

我的解决方法如下:

(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
 'hp' AS source FROM is_log AS l WHERE l.account_id = 730
 ORDER BY l.zeitpunkt DESC LIMIT 10)

UNION

(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
 'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730
 ORDER BY l.zeitpunkt DESC LIMIT 10)

ORDER BY zeit DESC LIMIT 10;
Run Code Online (Sandbox Code Playgroud)

我期望查询引擎会在这里使用索引,因为两个子查询都应该在 之前进行排序和限制UNION,然后合并和排序行。

我真的以为就是这样,但是EXPLAIN在查询上运行告诉我子查询仍然搜索两个表。

EXPLAINing子查询本身向我展示了所需的优化,但UNIONing它们在一起却没有。

我错过了什么?

我知道子查询中的ORDER BY子句在UNION没有 a 的情况下会被忽略LIMIT,但有一个限制。

编辑:
实际上,可能还会有没有account_id条件的查询。

这些表已经存在并且填充了数据。根据来源的不同,布局可能会发生变化,因此我想将它们分开。此外,日志客户端出于某种原因使用不同的凭据。

我必须在日志阅读器和实际表之间保留一层。

以下是整个查询和第一个子查询的执行计划以及详细的表布局:

https://gist.github.com/ca8fc1093cd95b1c6fc0

ype*_*eᵀᴹ 10

只是出于好奇,你能试试这个版本吗?它可能会欺骗优化器使用子查询单独使用的相同索引:

SELECT *
FROM
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt AS zeit,
 'hp' AS source FROM is_log AS l WHERE l.account_id = 730
 ORDER BY l.zeitpunkt DESC LIMIT 10) 
    AS a

UNION ALL

SELECT *
FROM
(SELECT l.id, l.account_id, l.vnum, l.count, l.preis, l.zeitpunkt,
 'ig' AS source FROM ig_is_log AS l WHERE l.account_id = 730
 ORDER BY l.zeitpunkt DESC LIMIT 10)
    AS b

ORDER BY zeit DESC LIMIT 10;
Run Code Online (Sandbox Code Playgroud)

我仍然认为你能拥有的最好的索引是复合(account_id, zeitpunkt)。它会快速产生 10 行,不需要任何技巧。