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_id
为12345
,您可以使用它来获取下一页,如下所示:
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=]
我有 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_id
为12345
,您可以使用它来获取下一页,如下所示:
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=]