PHP system()使用MySQL在许多数据库上运行查询

时间:2016-05-06 07:16:51

标签: php mysql database

我在下面有一个脚本,它通过380个MySQL innodb数据库并运行各种创建表,插入,更新等来迁移模式。它从连接到云数据库服务器的Web服务器运行。我将迁移脚本从这个问题中删除,因为我认为它不相关。

我遇到了一个问题,我正在努力寻找解决方法。

我有一个运行MySQL 5.6的4gb ram云数据库服务器。我将380个数据库与40个表迁移到59个表。大约70%的通过我得到了以下错误。它在一次迁移过程中死亡,服务器崩溃了。我正在观察内存使用情况,内存不足。它是一个数据库即服务,所以我没有root权限访问服务器所以我不知道所有细节。

在phppoint_smg上运行查询

Warning: Using a password on the command line interface can be insecure.
ERROR 2013 (HY000) at line 355: Lost connection to MySQL server during query

在phppoint_soulofhalloween上运行查询

Warning: Using a password on the command line interface can be insecure.
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0

在phppoint_srvais上运行查询

Warning: Using a password on the command line interface can be insecure.
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 0

这是PHP脚本的简化版本。

db_host = escapeshellarg($db_host);
$db_user = escapeshellarg($db_user);
$db_password = escapeshellarg($db_password);
foreach($databases as $database)
{
    echo "Running queries on $database\n***********************************\n";
    system("mysql --host=$db_host --user=$db_user --password=$db_password --port=3306 $database < ../update.sql"); 
    echo "\n\n";
}

我的问题:

有没有办法避免内存使用量上升,因为我进行迁移?我一次只做一个数据库。或者表格和数据的添加是它上升的原因吗?

我能够使用服务器后记录并删除了80个数据库并完成了迁移。它有800 MB免费;我希望它能降到600mb。在迁移之前它是500mb

7 个答案:

答案 0 :(得分:2)

很明显,您的迁移SQL查询会终止服务器。似乎数据库只需要为这些操作提供低空闲RAM。 根据数据库文件大小和查询,它可以确保提高您的RAM使用率。 在不知道确切的服务器规格的情况下,数据库中的数据以及您在那里发出的查询都没有确切的答案可以帮助您。

答案 1 :(得分:2)

不是生成大量进程,而是生成一个文件,然后运行它。生成类似

的文件
$out = fopen('tmp_script.sql', 'w');
foreach($databases as $database)
{
    fwrite($out, "USE $database;\n");
    fwrite($out, "source ../update.sql;\n");
}
fclose($out);

然后,手动或以编程方式执行

mysql ... < tmp_script.sql

手动执行它可能更安全,这样PHP就可以了。

答案 2 :(得分:2)

您的PHP示例没有使用太多内存,并且它没有在数据库服务器上运行,这是一个失败的,对吧?所以问题在于你配置的MySQL参数。

根据您的Gist,并使用简单的MySQL memory calculator,我们可以看到您的MySQL服务最多可以使用3817MB的内存。如果服务器在发生错误时只有4GB,那很可能是因为这个原因(你需要为操作系统和运行的应用程序增加一些内存)。增加内存或微调服务器将解决它。请查看MySQL documentation page on server variables以最好地了解每个值。

但是,这可能不是断开连接/超时的唯一原因(但似乎确实如此,因为增加内存可以解决问题)。另一个常见问题是低估max_allowed_packet值(配置中为16MB),因为此类脚本可以轻松查询超出此值的查询(例如,如果单个INSERT INTO table ...有多个值)。 / p>

考虑max_allowed_packet应该大于您向数据库发出的最大命令(它不是SQL文件,而是其中的每个命令,;之间的块)。

但请注意,请考虑进行更仔细的调整,因为配置错误的服务器可能会突然崩溃或无响应 - 而它可以在不添加更多内存的情况下完美运行。我建议运行性能调优脚本,如MySQLTuner-perl,它将分析您的数据,索引使用情况,查询速度慢,甚至提出优化服务器所需的调整。

答案 3 :(得分:1)

你应该尝试减轻你的RAM,因为你的服务器显然RAM非常低,一旦循环完成,就会在取消设置大数组后强制进行垃圾收集。

我在PHP7(以及RAM的512Go)下遇到了与PTHREADS类似的问题,该问题处理了在大型服务器上与MariaDB和Postgresql的1024个异步连接。

为每个循环尝试此操作。

//first unset main immediately at loop start:
unset($databases[$key]);

// second unset process and purge immediately
unset($database);
gc_collect_cycles();

此外,设置一个控件以持续监视加载下的RAM使用情况,以查看是否在特定的$ database上发生了这种情况。如果您的RAM太低,请将控件设置为chunk $ database并执行多次插入批处理并在完成后取消设置。这将清除更多RAM并避免在子插入循环之前过大的阵列副本。如果您使用带有构造的类,则尤其如此。使用4Go,我倾向于设置400到500个批处理异步插入最大值,取决于您的插入全局长度。

答案 4 :(得分:1)

如果您的数据库服务器崩溃(或被oom杀手杀死),那么原因是它已被配置为使用比设备上可用内存更多的内存。

您忘了告诉我们数据库节点上运行的操作系统。

如果您没有服务器的root访问权限,则这是配置它的任何人的错误。内存过量使用应为disabled(需要root访问权限)。像mysqltuner这样的工具将显示DBMS配置使用多少内存(需要管理员权限)。另请参阅this percona post

答案 5 :(得分:1)

我认为他们对ram是正确的,但值得注意的是你使用的工具很重要。

你试过http://www.mysqldumper.net/ 如果你使用它(PHP脚本)检查php内存限制的设置,让它自动检测。

我曾经使用http://www.ozerov.de/bigdump/ 但它太慢了,我不再了。

另一方面,mysqldumper在备份和恢复时都很快,没有崩溃(如果你设置了内存限制)

我发现这个工具很特别。

答案 6 :(得分:-2)

更新

你的评论完全改变了这种情况 这是我更新的答案:

由于您无法访问MySQL服务器,因此您需要采取一些替代方法。

强制从导入文件中删除所有特殊“事物”这样的封闭事务,插入延迟/忽略等等。

使用单一陈述强制执行SQL - 我不知道插入是怎么样的,但是单个语句 - 单个插入 - 不要在单个语句中捆绑很多行,

e.g。

而不是

insert into x
             (...fields...)values(...single row...),
             (...fields...)values(...single row...), 
             (...fields...)values(...single row...), 
             (...fields...)values(...single row...)
;

DO

insert into x(...fields...)values(...single row...); 
insert into x(...fields...)values(...single row...); 
insert into x(...fields...)values(...single row...); 
insert into x(...fields...)values(...single row...); 

然后试试这些:

  • 您可能会尝试使用大缓冲区“上传”my.ini,依此类推。 MySQL服务器的提供者可能会为您提供更多的RAM。毕竟是服务:)

  • 您可能会尝试生成包含架构的文件和包含数据的文件。然后导入模式,然后开始逐表导入并查看它崩溃的位置并恢复崩溃的文件。

  • 您可以使用MyISAM表导入所有内容。然后,您可以在InnoDB中转换这些内容。 alter table x engine=innodb。但是,这样做会失去所有参照完整性,您需要在以后强制执行。

  • 您可以使用MyISAM表导入所有内容。然后,您可以执行

  • 而不是转换它们

每张桌子都是这样的:

alter table x rename to x_myisam;
create table x(...);
insert into x select * from x_myisam;

我相信有一张桌子可以打破这个过程。如果找到它,您可以手动进行。例如,一次导入10000行或其他东西。

替代方法

如果您的服务器位于Amazon AWS或类似服务中,您可以尝试“扩展”(“放大”)导入服务器,并在导入完成后“缩小”(“缩小”)。

旧答案

  

为什么使用php脚本?尝试通过php创建或生成一个shell脚本。然后运行shell脚本。

     

在系统上创建巨大的交换文件也非常重要。这是   一种方法。它可能不适用于旧系统:

sudo su # became root
cd /somewhere
fallocate -l 16gb file001
mkswap file001
chmod 0 file001
swapon file001
     

然后执行php或shell脚本。

     

完成后,您可以交换并删除文件或将其永久保存   在fstab。

     

如果我需要澄清任何事情,请告诉我。