MySQL 自联接表 Next/Prev 行性能

Posted

技术标签:

【中文标题】MySQL 自联接表 Next/Prev 行性能【英文标题】:MySQL Self Join Table Next/Prev Row Performance 【发布时间】:2021-03-07 12:31:53 【问题描述】:

我有一个表,其中有一列 Sequence 提供表的排序。我正在尝试根据Sequence 将下一行和上一行连接在一起,以便我可以获得上一个和下一个 SKU 值。

表定义如下:

CREATE TABLE `Builder` (
    `Shipment Number` VARCHAR(50) NULL DEFAULT NULL,
    `SKU` VARCHAR(50) NULL DEFAULT NULL,
    `Pallet Number` VARCHAR(50) NULL DEFAULT NULL,
    `Sequence` INT NULL DEFAULT NULL,

    INDEX `Primary Index` (`Shipment Number`, `Pallet Number`, `Sequence`) USING BTREE
)

我的查询目前看起来像这样用于计算下一行 SKU 值:

SELECT
    B1.`SKU`,
    B1.`Shipment Number`,
    B1.`Pallet Number`,
    B1.`Sequence`,
    B2.`SKU`
FROM Builder B1

LEFT JOIN Builder B2 ON
    B2.`Sequence.` = (
        SELECT MIN(B3.`Sequence.`)
        FROM Builder B3
        WHERE
            B3.`Sequence` > B1.`Sequence` AND
            B3.`Shipment Number` = B1.`Shipment Number` AND
            B3.`Pallet Number` = B1.`Pallet Number`
    ) AND
    B1.`Shipment Number` = B2.`Shipment Number` AND
    B1.`Pallet Number` = B2.`Pallet Number`

我在Builder 表中为(Sequence, Shipment Number, Pallet Number) 添加了一个索引。

该查询正确计算下一个 SKU,但性能非常糟糕,即使在我的完整数据集的一个子集(50,000 行)上运行也需要几分钟。我不确定是否可以做任何其他事情来提高此查询的性能。

mysql 8.0.20 上运行。

谢谢!

【问题讨论】:

提供完整的 CREATE TABLE 脚本(和数据示例,3-5 相邻行)和精确的 MySQL 版本。 如果您使用的是 MySQL 8.x,请考虑使用像 LAG() 这样的窗口函数。 除了SELECT MIN(Sequence),你也可以使用SELECT Sequence..... ORDER BY..... LIMIT 1 @Luuk 感谢您的建议。我尝试使用ORDER BYLIMIT 运行查询,但看起来性能比MIN 实现稍差。 @Barmar 我试图避免使用窗口函数,因为业务要求是在 ANSI sql 中。 WHERE 子句吗?还是你想把整张桌子都扔掉? 【参考方案1】:

使用 LEAD()LAG() 代替连接。它们就是为此而生的。

例如:

select
  *,
  lag(`SKU`) over(partition by `Shipment Number`, `Pallet Number`
                  order by `Sequence`) as prev_sku,
  lead(`SKU`) over(partition by `Shipment Number`, `Pallet Number`
                   order by `Sequence`) as next_sku
from builder

LAG()根据指定的条件(partitionordering)返回上一行的值,而LEAD()返回下一行的值根据指定的标准。

您还可以添加一个可选的第二个参数(一个默认为 1 的整数)来指示您想要查看的距离(行)。

【讨论】:

这比我的实现要快得多。谢谢!

以上是关于MySQL 自联接表 Next/Prev 行性能的主要内容,如果未能解决你的问题,请参考以下文章

Mysql 自联接性能

SQLAlchemy 通过关联对象声明性多对多自联接

自联接的困难 MySQL 更新查询

SQLAlchemy:在 MySQL 上使用自联接创建删除查询

选择 3 行包含不同值的列 - 自联接?

MPMoviePlayerController - 检测按下 Next/Prev 按钮