3

我正在使用 mysql 并希望处理一个非常大的表,其主键由 10,000 个块中的 4 个部分组成(将数据编组到另一个系统)。当我进行处理时,数据库处于脱机状态,因此我不必担心任何修改。假设主键是 ( 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;

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

4

4 回答 4

3

从一开始就使用简单的方法开始处理数据

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)

LIMIT 10000(如果您不想依赖客户端代码过早退出 fetch 循环,也可以添加子句)。这个解决方案的关键是 MySQL 正确地实现了元组比较。

编辑:提到LIMIT 10000可以添加可选。

于 2012-11-03T21:16:18.100 回答
1

您可能正在以某种方式调用表的顺序扫描。

此外,您是有条件的SELECT没有按照您的想法进行操作。它在第一个条件A > a上短路。

如果您跳过ORDER BYLIMIT并使用如下语句,效率会更高:

SELECT *
FROM LargeTable
WHERE A = a AND B = b AND C = c;

并且只需遍历abc的集合。

于 2012-11-03T21:11:41.957 回答
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
}
于 2012-11-03T21:10:09.377 回答
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;
于 2012-11-03T21:45:24.513 回答