MySQL:按块检索大选择

Posted

技术标签:

【中文标题】MySQL:按块检索大选择【英文标题】:MySQL : retrieve a large select by chunks 【发布时间】:2016-03-14 19:44:53 【问题描述】:

我有更多的选择

7000 万行

我想在win2012 R2上将选定的数据保存到一个大的csv文件中

问:如何通过 chanks 从 mysql 中检索数据以获得更好的性能?

因为当我尝试保存一个大选择时,我得到了

内存不足错误

【问题讨论】:

【参考方案1】:

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

SELECT * FROM MyTable ORDER BY whatever LIMIT 0,1000

您将获得前 1000 行。第一个LIMIT 值(0) 定义结果集中的起始行。它是零索引的,所以 0 表示“第一行”。第二个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 没有返回任何行时,您就完成了。

但这本身是不够的,因为在您一次处理 1K 行时对表所做的任何更改都会导致订单失效。要及时冻结结果,首先将结果查询到临时表中:

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

旁注:最好事先确保临时表不存在:

DROP TEMPORARY TABLE IF EXISTS MyChunkedResult;

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

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

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

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

DROP TEMPORARY TABLE MyChunkedResult;

【讨论】:

如何循环播放? @Pixar 基本上取决于您打算使用哪种技术。您可以使用CREATE procedure 直接在 MySQL 中执行它,或者另一种好方法是在 php 和 python 中使用一段时间循环和您要选择的数据的特定块大小来执行它。我的建议是将 pipestreamnode 一起使用,这是值得的方法。 这种方法不适用于大表,只有小表才能这样工作。 我搜索的太多了。我认为这是最好的简单答案。 @Aaron 使用 OFFSET 也不适用于大表。我已经在这些任务上投入了几个月的时间,唯一的解决方案是拥有一个可以手动通过的主数字键。 “其中 id 在 a 和 a+10000 之间” a+=10000;问题是 mysql 太愚蠢了,无法正确完成此类任务。它不记得任何内部指针,因此您无法从停止的地方继续。【参考方案2】:

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

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

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

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

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

【讨论】:

如何获取最后一行? @tanteng 我在 python 中进行分页。所以,我将结果存储在一个 python 集合对象中,并用它来获取最后一行。【参考方案3】:

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

【讨论】:

【参考方案4】:

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

简而言之:它在读取数据库时写入 CSV/文件。

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

Read this 了解有关MYSQLI_USE_RESULT 的更多信息,请小心,因为在函数运行时您可能无法在数据库上执行其他任务/查询

【讨论】:

以上是关于MySQL:按块检索大选择的主要内容,如果未能解决你的问题,请参考以下文章

MySQL必知必会---检索数据

带有内部选择查询的 MySQL 搜索

MySQL基础:检索数据

Mysql必知必会 检索数据

MySQL必知应会-第4章-检索数据

在python中按块解压缩文件夹