Mysql left join with nested select慢,如何优化

Posted

技术标签:

【中文标题】Mysql left join with nested select慢,如何优化【英文标题】:Mysql left join with nested select slow, how to optimize 【发布时间】:2021-08-01 00:47:50 【问题描述】:

我有一个执行速度很慢的 LEFT JOIN mysql 查询,我正在寻找改进。 我有一个表“VM”列出了“VmId”(+ 一些其他数据)和另一个表“VM_Status”列出了 VM 的状态(上/下),每一行都有一个“inputDate”。

表 VM 为 7.000 行,表 VM_Status 为 76.000 行

我需要选择 7.000 VM 的最新状态

我的查询如下,执行需要 25 秒:

SELECT 
VM.*,
`VM_Status`.`Status` AS `Status`
FROM VM
left join (
   select
       * 
   from
       `VM_Status` `s1`
   where
       (
           `s1`.`InputDate` = (
               select
                   max(`s2`.`InputDate`)
               from
                   `VM_Status` `s2`
               where
                   (`s1`.`VmId` = `s2`.`VmId`)
           )
       )

) `VM_Status` on(
   (
       `VM_Status`.`VmId` = `WORKLOAD`.`VmId`
   )
)

我怎样才能更快地做到这一点?

【问题讨论】:

查看添加的标签。 【参考方案1】:

您可以使用窗口函数。Window Functions in MySQL

MySQL 支持窗口函数,对于查询中的每一行,使用与该行相关的行执行计算。

在您的情况下,您可以使用带有 order by 子句的 RANK() 或 DENSE_RANK() 函数,并在窗口内获取该 MAX(避免慢速连接)。 见:RANK

类似的东西:

select 
    *
from (
SELECT 
    VM.*,
    `VM_Status`.`Status` AS `Status`,
    RANK() OVER(PARTITION BY `VM_Status`.`VmId` ORDER BY `VM_Status`.`InputDate` DESC) rank
    FROM VM left join `VM_Status`
    ON `VM_Status`.`VmId` = `VM`.`VmId`
) `last_status`
WHERE 
    rank = 1

【讨论】:

谢谢,我不知道 RANK()。但是我在 5.7 版上,我的东西 RANK() 仅在 8 上可用。我尝试了一个替代方案,但它从 1 级到 78.000 级返回了 78.000 行......我错过了什么? select * from ( SELECT VM.VmId, VM_Status.Status AS Status, @curRank := @curRank + 1 AS Rank FROM (SELECT @curRank := 0) r, VM 离开加入 VM_Status ON VM_Status.VmId = VM .VmId ORDER BY VM_Status.InputDate DESC ) last_status ORDER BY Rank

以上是关于Mysql left join with nested select慢,如何优化的主要内容,如果未能解决你的问题,请参考以下文章

Mysql LEFT JOIN with count 返回未知列

MySQL left join with 'b's limit

mysql left join to table with multiple rows on min id 以确保返回单行

谁能真正理解hash join/nested loop/merge join

MySQL LEFT JOIN with SUM before a date and SUM before and at that date

Mysql JOIN with IN 和 RIGHT 表的多个结果