简体   繁体   English

PHP PDO Mysql插入性能

[英]PHP PDO Mysql Insert Performance

I normally don't use a lot of SQL stuff in PHP but recently have been forced into it by a friend as to help him debug something. 我通常不会在PHP中使用很多SQL东西,但是最近我被一位朋友强迫使用它来帮助他调试某些东西。

I am using PDO with PHP to insert some data but the insert performance is abysmal. 我在PHP中使用PDO插入一些数据,但是插入性能却很糟糕。 A simple loop of 151 inserts takes nearly 6 seconds! 一个简单的151次插入循环需要将近6秒钟! and I am lost as to why. 我不知道为什么。

Here is my code: 这是我的代码:

<?php

$database='XXXXXX';
$username='XXXXXX';
$password='XXXXXX';
$hostname='127.0.0.1';

$inserted=0;
$counted=0;
$dsn = 'mysql:dbname='.$database.';host='.$hostname.'';
$start=microtime(true);
try {
    $data = new PDO($dsn, $username, $password, array(PDO::ATTR_EMULATE_PREPARES => false));
} catch (PDOException $e) {
    echo('Connection failed: ' . $e->getMessage());
}
for($i=1;$i<=150;$i++) {
    $time=time();
    $query=$data->prepare("INSERT INTO `tbl_temp` (aid, bid) VALUES (?, ?)");
    $query->execute(array($i, $time));
}
$data=null;
print "Took: ".(microtime(true)-$start)." S to insert $i records\n";

// Took: 5.569482088089 S to insert 151 records <--- result
?>

I have tried the same code using bindParam also and the speed is roughly the same. 我也使用bindParam尝试了相同的代码,并且速度大致相同。 The server has an 8 core Xeon processor and 64gb of RAM. 该服务器具有8核Xeon处理器和64GB RAM。 The script is being run from the command line (php-cgi) and the database and table are new and empty. 该脚本是从命令行(php-cgi)运行的,数据库和表是新的并且为空。 The database type is InnoDB. 数据库类型为InnoDB。 Can anyone point me in the right direction of where to look as to why it's so slow? 谁能指出我为什么会这么慢的正确方向? Because I am sure MySQL never used to be this slow! 因为我敢肯定MySQL从来没有这么慢!

found this one. 找到了这个。 Performance in PDO / PHP / MySQL: transaction versus direct execution . PDO / PHP / MySQL中的性能:事务与直接执行 so try this one. 所以尝试这个。

$query = $data->prepare("INSERT INTO `tbl_temp` (aid, bid) VALUES (?, ?)");
try {
        $data->beginTransaction();
        for($i=0; $i < 150; $i++) {
            $time = time();
            $query->bindValue(1, $i, PDO::PARAM_INT);
            $query->bindValue(2, $time, PDO::PARAM_STR);
            $query->execute();
        }
        $data->commit();
    } catch(PDOException $e) {
            $data->rollBack();
    }

Turns out that a setting inside the SQL server is what was causing it. 事实证明,SQL服务器内部的设置是引起它的原因。 As far as I can tell the transaction commit was set to flush to disk on every write: 据我所知,在每次写操作时,事务提交已设置为刷新到磁盘:

innodb_flush_log_at_trx_commit=0

This is the default ACID compliant settings of a new install. 这是新安装的默认ACID兼容设置。

I changed my setting to this 我将设置更改为此

innodb_flush_log_at_trx_commit=2

This allows ONLY power outage or OS crash to erase the transaction buffer/log and not a mysqld crash. 这仅允许断电或OS崩溃来擦除事务缓冲区/日志,而不是mysqld崩溃。

For some people who need the "D" of ACID to be 100% true then you should leave this setting alone. 对于某些需要ACID的“ D”为100%真实的人,则应保留此设置。

As Simon stated in a comment, there is no use of doing the preparation within the loop. 正如西蒙(Simon)在评论中所说,在循环中没有任何准备工作。 Doing so will cause 300 queries to be sent to the database, each time one for the preparation and on for the actual insert. 这样做将导致向数据库发送300个查询,每次查询一次进行准备,然后进行实际插入。 Using the prepare-statement before will cause only 151 queries: 之前使用prepare语句将仅导致151个查询:

$query = $data->prepare("INSERT INTO `tbl_temp` (aid, bid) VALUES (?, ?)");
for ($i = 1; $i <= 150; $i++) {
    $time = time();
    $query->execute(array($i, $time));
}

Another idea could be to use instead a combined multi insert statement. 另一个想法可能是使用组合的多插入语句。 I guess it could have a better performance, but I'm not quite sure: 我想它可能会有更好的性能,但我不确定:

$query = 'INSERT INTO `tbl_temp` (aid, bid) VALUES';
for ($i = 1; $i <= 150; $i++) {
    if ($i == 1) {
        $query .= ' ('.$i.', '.time().')';
    } else {
        $query .= ', ('.$i.', '.time().')';
    }
}
$data->exec($query);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM