MySQL :按块检索大 select

MySQL : retrieve a large select by chunks

我有 select 还有更多

70 milion rows

我想将 selected 数据保存到 win2012 R2

上的一个大 csv 文件中

问:如何按块从 MySQL 中检索数据以获得更好的性能?

因为当我试图保存一个大的 select 我得到了

out of memory errors

您可以尝试使用 LIMIT 功能。如果你这样做:

SELECT * FROM MyTable ORDER BY whatever LIMIT 0,1000

您将获得前 1,000 行。第一个 LIMIT 值 (0) 定义结果集中的起始行。它是零索引的,所以 0 表示 "the first row"。第二个 LIMIT 值是要检索的最大行数。要获得接下来的几组 1,000,请执行以下操作:

SELECT * FROM MyTable ORDER BY whatever LIMIT 1000,1000 -- rows 1,001 - 2,000
SELECT * FROM MyTable ORDER BY whatever LIMIT 2000,1000 -- rows 2,001 - 3,000

等等。当 SELECT returns 没有行时,你就大功告成了。

但这本身还不够,因为在您一次处理 1K 行时对 table 所做的任何更改都会打乱顺序。要及时冻结结果,首先将结果查询到临时 table:

CREATE TEMPORARY TABLE MyChunkedResult AS (
  SELECT *
  FROM MyTable
  ORDER BY whatever
);

旁注:确保临时 table 事先不存在是个好主意:

DROP TEMPORARY TABLE IF EXISTS MyChunkedResult;

无论如何,一旦临时 table 到位,从那里拉出行块:

SELECT * FROM MyChunkedResult LIMIT 0, 1000;
SELECT * FROM MyChunkedResult LIMIT 1000,1000;
SELECT * FROM MyChunkedResult LIMIT 2000,1000;
.. and so on.

我将留给您创建逻辑来计算每个块后的限制值并检查结果的结尾。我还建议使用比 1,000 条记录大得多的块;这只是我从空中挑选的一个数字。

最后,完成后删除临时 table 是一个很好的形式:

DROP TEMPORARY TABLE MyChunkedResult;

当数据量很大时,LIMIT OFFSET 方法会减慢查询速度。另一种方法是使用称为键集分页的东西。它在您的查询中需要一个唯一的 ID,您可以将其用作书签以指向上一页的最后一行。使用上一个书签获取下一页。例如:

SELECT user_id, name, date_created
FROM users
WHERE user_id > 0
ORDER BY user_id ASC
LIMIT 10 000;

如果returns上面的结果集最后一行user_id12345,您可以使用它来获取下一页,如下所示:

SELECT user_id, name, date_created
FROM users
WHERE user_id > 12345
ORDER BY user_id ASC
LIMIT 10 000;

更多详情,你可以看看这个page

对于如此大的数据集,为了避免对输出进行分块的需要,另一种方法是将相关数据查询到它自己的新 table(不是临时 table)中,只包含您需要的数据,然后使用 mysqldump 处理导出到文件。

使用 MYSQLI_USE_RESULT 的无缓冲结果集能够读取数据库并执行诸如逐行将输出写入 CSV 文件的功能。

简而言之:它在从数据库读取的同时写入 CSV/File。

当使用 mysqli_query 时,它默认使用 MYSQLI_USE_STORE 并读取整个数据库并获取导致内存使用过多的结果集。

Read this 有关 MYSQLI_USE_RESULT 的更多信息,请注意,当函数为 运行[= 时,您可能无法在数据库上执行其他 tasks/queries 15=]