【问题标题】:PHP PDO Mysql Insert PerformancePHP PDO Mysql 插入性能
【发布时间】:2014-11-24 17:12:23
【问题描述】:

我通常不会在 PHP 中使用很多 SQL 的东西,但最近被朋友强迫使用它来帮助他调试一些东西。

我正在使用 PDO 和 PHP 来插入一些数据,但插入性能很糟糕。一个简单的 151 次插入循环需要将近 6 秒!我不知道为什么。

这是我的代码:

<?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
?>

我也尝试过使用 bindParam 的相同代码,速度大致相同。该服务器具有 8 核 Xeon 处理器和 64gb 内存。该脚本正在从命令行(php-cgi)运行,并且数据库和表是新的并且是空的。数据库类型是 InnoDB。谁能指出我在哪里寻找它为什么这么慢的正确方向?因为我确信 MySQL 从来没有这么慢过!

【问题讨论】:

  • 在循环外准备 sql 会有所帮助。我认为问题更可能出在您的表结构中。您的表格结构和当前内容是什么?
  • 嗨。我的结构是这样的...code id -> AI Primary Key,aid -> Int, bid -> Int 我当前的内容是零行就是这样:)
  • 只是一个建议,对上述查询进行解释并观察它的瓶颈所在。可能有用还是没用......
  • Mysql insert,updates very slow 的可能重复项
  • @ThinkingWeb。没有用,我已经试过了。插入查询真的没有比这更简单的了。此外,这与您放置的链接的可能副本相去甚远,因此我不确定您为什么将其放在那里。

标签: php mysql pdo prepared-statement innodb


【解决方案1】:

找到了这个。 Performance in PDO / PHP / MySQL: transaction versus direct execution。所以试试这个。

$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();
    }

【讨论】:

  • 这个例子是为哪个版本的 PHP 编写的?在 PHP 7 中,mysqli 对象使用 begin_transaction()bind_param()rollback,而不是您使用的函数名称。
  • @Kenny83 整篇文章都是关于使用 PDO 和准备好的语句。你为什么说mysqli
【解决方案2】:

原来是 SQL 服务器内部的一个设置导致了它。据我所知,事务提交设置为在每次写入时刷新到磁盘:

innodb_flush_log_at_trx_commit=0

这是新安装的默认 ACID 兼容设置。

我把设置改成了这个

innodb_flush_log_at_trx_commit=2

这仅允许断电或操作系统崩溃来擦除事务缓冲区/日志,而不是 mysqld 崩溃。

对于某些需要 ACID 的“D”为 100% 正确的人,您应该不理会此设置。

【讨论】:

  • ...或者使用更快的存储空间..或者不使用隐式事务。
【解决方案3】:

正如西蒙在评论中所说,在循环中进行准备是没有用的。这样做会导致向数据库发送 300 个查询,每次一个用于准备,一个用于实际插入。之前使用prepare-statement只会导致151个查询:

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

另一个想法可能是使用组合的多插入语句。我想它可以有更好的性能,但我不太确定:

$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);

【讨论】:

  • 好的。尝试了第一个,性能是一样的。第二个我无法尝试,因为它没有进行绑定参数化。我的示例是实际正在执行的操作的缩减版本,尽管性能大致相同并且插入的数量大致相同。
猜你喜欢
  • 1970-01-01
  • 2018-02-18
  • 2013-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多