【发布时间】:2021-05-31 22:23:42
【问题描述】:
-
MySQL 8.0.25(主要使用 HeidiSQL,但有时也使用命令行)
-
Windows 10(专用 MySQL 机器)
-
128GB 内存
-
用于操作系统和数据驱动器的单独 SSD
-
Temp DIR 指向具有 600GB 可用空间的数据驱动器
-
我正在查询的数据超过 8200 万行,大小约为 18GB
我有什么
| ID | signal |
|---|---|
| 1 | x |
| 2 | x |
| 3 | y |
| 4 | x |
| 5 | y |
| 6 | y |
| 7 | y |
| 8 | x |
| 9 | y |
| 10 | x |
| 11 | y |
我需要什么
| X ID | Y ID |
|---|---|
| 1 | 3 |
| 4 | 5 |
| 8 | 9 |
| 10 | 11 |
解释:
基本上,我在单列中有一个变量列表(X 和 Y)。我需要找到 X,然后在 X 的行之后找到带有 Y 的下一行。但是,有时,如上例所示,有多个 X 和 Y 相互重复(即第 1 行和第 2 行)。我需要第一个 X,然后是第一个 Y(并跳过重复 X 的行)。
下一个选择的 X 将位于先前使用的行中的 Y 之后。即,第 4 行的 X 将是第一个结果行之后的下一个,并且永远不会使用第 2 行中的 X。
我试过了:
SELECT
x_tbl.id,
(
SELECT
y_tbl.id
FROM
t_table AS y_tbl
WHERE
signal = "y"
AND
MIN(y_tbl.id) > x_tbl.id
LIMIT
1
) y_id
FROM
t_table AS x_tbl
WHERE
x_tbl.signal = "x"
问题是 InnoDB 会重新扫描整个数据库。单身的。排。我的真实代码是从原始表中提取数据,然后通过一些 CTE 过滤掉数据量,然后再执行此步骤(例如数据等)。从我的测试来看,这确实有助于加快速度——但在整个数据库中运行它实际上需要 10 多天才能完成。太疯狂了。
有没有更有效的方法来写这个?
【问题讨论】:
-
这些方面的东西怎么样...stackoverflow.com/questions/67553864/…
-
感谢您的回复!在理解您的示例时,我大约有 75% 的人在那里 - 但不完全确定为什么在“grp”字段中,您要减去一个密集排名(用户 ID)和组合密集排名(用户 ID、状态)。你能解释一下如何/为什么这样做吗?我怀疑这与将“最新”状态更改置于更高/更低级别有关 - 但不完全确定......
-
请参阅db-fiddle.com/f/3PS7gV64j1gkXdbvgtPKC8/0 了解一些细分...这里我们对状态更改感兴趣。每当 x 减去 y 的结果与“上一个”行中的结果不同时,就会发生这种情况。
-
这太棒了,顺便说一句。但是,如果我想包括状态更改本身的日期(即在您的示例中,不是开始和结束日期具有相同的状态,我想要第一个状态的开始日期,然后“更改”状态本身的日期作为完成日期)?我会使用某种将 1 添加到完成日期行,或者可能是 LEAD(MIN(date)) 类型的东西吗?只是为了澄清-我想要的输出是:| 1 | GRE | 2018-09-02 | 2018-09-04 | | 1 |专业 | 2018-09-04 | 2018-09-07 |谢谢!
-
这听起来完全不同,足以证明一个问题本身。好消息是,您现在可以使用工具来提出这个问题。
标签: mysql