处理复合主键顺序中的记录块

时间:2012-11-03 20:36:04

标签: mysql sql

我正在使用mysql,并希望处理一个非常大的表,主键为4个部分,块数为10,000(将数据编组到另一个系统)。我正在进行处理时数据库处于脱机状态,所以我不必担心任何修改。假设主键是(ABCD),它们都是整数。我首先尝试使用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 = aB = bC = cD = 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;

然后对每个块重复一遍。当我到达表中较高的行时,这似乎也大大减慢了。有一个更好的方法吗?我错过了一些明显的东西吗?

4 个答案:

答案 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;