归档 mysql 数据抛出内存限制问题
Archiving mysql data throwing memory limit issue
我有多个 table。像 table1、table2、table3 等
需要什么:
1. 从 table1 获取特定行。 (例如:id = 203)
2. 从 table2 获取与 id 203 相关的所有值(例如:1,2,3,4,5,6,7....500)
3. 再次从 table3、table4 等中获取步骤 2 中的所有 ID 值,这些值在 table2 上具有外键关系。(百万行)
4. 从结果构建上述所有 3 个步骤的插入语句。
5. 在具有相同 table 名称的存档数据库中的相关 table 中插入步骤 4 的查询。即,简而言之,将部分数据归档到归档DB。
我过得怎么样:
对于每个 table,无论何时获取行,都会为每个 table 创建插入语句并存储在特定数组中。一旦获取所有值直到第 3 步,创建插入语句并存储在数组中。然后 运行 循环每个单独的数组并执行这些查询归档数据库。一旦查询成功执行,从主数据库中删除所有获取的行,然后提交事务。
结果:
到目前为止,上述方法对于大约 10-20mb 数据的小型数据库非常有效。
问题:
对于更大数量的行(比如超过 5gb),php 在获取行时抛出内存耗尽错误,因此在生产环境中不起作用。即使我将内存限制增加到 3gb。我不想再增加了。
我想到的替代解决方案是,不是使用数组来存储查询,而是将这些查询存储在文件中,然后在内部使用 infile 命令执行查询以存档数据库。
请指教如何实现上述问题?移至存档数据库后,需要移回具有类似功能的主数据库。
处理大型结果集有两个关键。
首先是逐行流式传输结果集。除非您明确指定,否则 MySQL 的 php API 会立即尝试将整个结果集从 MySQL 服务器读取到客户端内存中,然后逐行浏览该结果集。如果您的结果集有数万或数十万行,这可能会使 php 运行 内存不足。
如果您使用的是 mysql_
界面,请使用 mysql_unbuffered_query()
。不过,您不应该使用该界面。它已被弃用,因为它很糟糕。
如果您使用的是 mysqli_
界面,请调用 mysqli_real_query()
instead of mysqli_query()
. Then call mysqli_use_result()
to initiate retrieval of the result set. You can then fetch each row with with one of the fetch()
variants。获取所有行后,不要忘记使用 mysqli_free_result()
关闭结果集。 mysqli_
有面向对象的方法;你也可以使用它们。
PDO 具有类似的方式将结果集从服务器流式传输到客户端。
处理大型结果集的第二个关键是使用第二个连接到您的 MySQL 服务器来执行 INSERT
和 UPDATE
操作,这样您就不必累积他们在记忆中。如果您选择将信息写入文件系统中的文件,情况也是如此:一次写入一行,这样您就不必将其保存在 RAM 中。
诀窍是一次处理一行或几行,而不是数万行。
不得不说:对于这种数据库维护,很多人更喜欢使用Java、C#、PERL等number-c运行ching语言编写的命令行程序。
我有多个 table。像 table1、table2、table3 等
需要什么:
1. 从 table1 获取特定行。 (例如:id = 203)
2. 从 table2 获取与 id 203 相关的所有值(例如:1,2,3,4,5,6,7....500)
3. 再次从 table3、table4 等中获取步骤 2 中的所有 ID 值,这些值在 table2 上具有外键关系。(百万行)
4. 从结果构建上述所有 3 个步骤的插入语句。
5. 在具有相同 table 名称的存档数据库中的相关 table 中插入步骤 4 的查询。即,简而言之,将部分数据归档到归档DB。
我过得怎么样:
对于每个 table,无论何时获取行,都会为每个 table 创建插入语句并存储在特定数组中。一旦获取所有值直到第 3 步,创建插入语句并存储在数组中。然后 运行 循环每个单独的数组并执行这些查询归档数据库。一旦查询成功执行,从主数据库中删除所有获取的行,然后提交事务。
结果:
到目前为止,上述方法对于大约 10-20mb 数据的小型数据库非常有效。
问题:
对于更大数量的行(比如超过 5gb),php 在获取行时抛出内存耗尽错误,因此在生产环境中不起作用。即使我将内存限制增加到 3gb。我不想再增加了。
我想到的替代解决方案是,不是使用数组来存储查询,而是将这些查询存储在文件中,然后在内部使用 infile 命令执行查询以存档数据库。
请指教如何实现上述问题?移至存档数据库后,需要移回具有类似功能的主数据库。
处理大型结果集有两个关键。
首先是逐行流式传输结果集。除非您明确指定,否则 MySQL 的 php API 会立即尝试将整个结果集从 MySQL 服务器读取到客户端内存中,然后逐行浏览该结果集。如果您的结果集有数万或数十万行,这可能会使 php 运行 内存不足。
如果您使用的是 mysql_
界面,请使用 mysql_unbuffered_query()
。不过,您不应该使用该界面。它已被弃用,因为它很糟糕。
如果您使用的是 mysqli_
界面,请调用 mysqli_real_query()
instead of mysqli_query()
. Then call mysqli_use_result()
to initiate retrieval of the result set. You can then fetch each row with with one of the fetch()
variants。获取所有行后,不要忘记使用 mysqli_free_result()
关闭结果集。 mysqli_
有面向对象的方法;你也可以使用它们。
PDO 具有类似的方式将结果集从服务器流式传输到客户端。
处理大型结果集的第二个关键是使用第二个连接到您的 MySQL 服务器来执行 INSERT
和 UPDATE
操作,这样您就不必累积他们在记忆中。如果您选择将信息写入文件系统中的文件,情况也是如此:一次写入一行,这样您就不必将其保存在 RAM 中。
诀窍是一次处理一行或几行,而不是数万行。
不得不说:对于这种数据库维护,很多人更喜欢使用Java、C#、PERL等number-c运行ching语言编写的命令行程序。