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 中使用一段时间循环和您要选择的数据的特定块大小来执行它。我的建议是将 pipe
和 stream
与 node 一起使用,这是值得的方法。
这种方法不适用于大表,只有小表才能这样工作。
我搜索的太多了。我认为这是最好的简单答案。
@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_id
为12345
,则可以使用它来获取下一页,如下所示:
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:按块检索大选择的主要内容,如果未能解决你的问题,请参考以下文章