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 BY
、LIMIT
运行查询,但看起来性能比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()
根据指定的条件(partition和ordering)返回上一行的值,而LEAD()
返回下一行的值根据指定的标准。
您还可以添加一个可选的第二个参数(一个默认为 1
的整数)来指示您想要查看的距离(行)。
【讨论】:
这比我的实现要快得多。谢谢!以上是关于MySQL 自联接表 Next/Prev 行性能的主要内容,如果未能解决你的问题,请参考以下文章