我正在使用mysql,并希望处理一个非常大的表,主键为4个部分,块数为10,000(将数据编组到另一个系统)。我正在进行处理时数据库处于脱机状态,所以我不必担心任何修改。假设主键是(A
,B
,C
,D
),它们都是整数。我首先尝试使用LIMIT OFFSET
来实现这一目标:
SELECT * FROM LargeTable ORDER BY (A, B, C, D) LIMIT 10000 OFFSET 0;
我在每次通话时将偏移量增加了10000。当它走向表中较高的行时,这似乎变得非常缓慢。是否无法有效地执行此操作LIMIT OFFSET
?
然后我尝试了一种在复合主键上使用比较的不同方法。我可以像这样得到第一个块:
SELECT * FROM LargeTable ORDER BY (A, B, C, D) LIMIT 10000;
如果该块的最后一行有A = a
,B = b
,C = c
和D = d
,那么我可以通过以下方式获取下一个块:
SELECT * FROM LargeTable
WHERE
A > a OR
(A = a AND B > b) OR
(A = a AND B = b AND C > c) OR
(A = a AND B = b AND C = c AND D > d)
ORDER BY (A, B, C, D) LIMIT 10000;
然后对每个块重复一遍。当我到达表中较高的行时,这似乎也大大减慢了。有一个更好的方法吗?我错过了一些明显的东西吗?
答案 0 :(得分:2)
使用普通的
从一开始就开始处理数据SELECT *
FROM LargeTable
ORDER BY (A, B, C, D)
并在客户端代码中逐个获取行。如果需要,可以在fetch循环中获取10000行,或者添加LIMIT 10000
子句。如果要停止此块,请记住已处理的最后一个元组(A,B,C,D),我们可以将其称为(A1, B1, C1, D1)
。
现在,当你想从最后一点重新启动时,逐个再次获取行,但这次在WHERE子句中使用元组比较:
SELECT *
FROM LargeTable
WHERE (A, B, C, D) > (A1, B1, C1, D1)
ORDER BY (A, B, C, D)
(如果您不想过早依赖客户端代码退出fetch循环,也可以添加LIMIT 10000
子句。
这个解决方案的关键是MySQL正确地实现了元组比较。
编辑:提到可以添加可选的LIMIT 10000
。
答案 1 :(得分:1)
您可能以某种方式调用表的顺序扫描。
此外,你是有条件的 SELECT 没有做你认为它做的事情。它在第一个条件下短路 A>一个
如果您跳过 ORDER BY 和 LIMIT 并使用如下语句,那将会更有效率:
SELECT *
FROM LargeTable
WHERE A = a AND B = b AND C = c;
只需遍历一组 a , b 和 c 。
答案 2 :(得分:0)
很大程度上取决于你正在进行'编组'操作的上下文,但有没有理由不让无约束的SELECT运行,并让你的代码分组成10,000个项目的块?
在伪代码中:
while (fetch_row succeeds)
{
add row to marshalled data
if (10,000 rows marshalled)
{
process 10,000 marshalled rows
set number of marshalled rows to 0
}
}
if (marshalled rows > 0)
{
process N marshalled rows
}
答案 3 :(得分:0)
使用偏移量限制需要丢弃行,直到找到实际需要的行,因此当你有更高的偏移量时它会变慢。
这是一个想法。由于数据库在执行此操作时处于脱机状态,因此在作业期间实际上不必存在数据。为什么不在处理它们时将所有已处理的行移动到另一个表?我不确定它会更快,这取决于表有多少索引,但你应该尝试一下。
CREATE TABLE processed AS LargeTable;
SELECT * FROM LargeTable LIMIT 10000;
INSERT INTO processed SELECT * FROM LargeTable LIMIT 10000;
DELETE FROM LargeTable LIMIT 10000;
DELETE TABLE LargeTable;
RENAME TABLE processed TO LargeTable;