Php 低性能MySql

Php 低性能MySql,php,mysql,mysqli,prepared-statement,Php,Mysql,Mysqli,Prepared Statement,我正在测试一个我正在构建的系统的性能,它真的很慢,我不知道为什么或者它是否应该这么慢。我测试的是我可以对数据库进行多少次单次插入,每秒大约22次。这听起来真的很慢,当我尝试插入一个大型SQL查询时,我可以在大约0.5秒内插入30000条记录。在现实生活中,插入是由系统中的不同用户进行的,因此连接、发送查询、解析查询等开销始终存在。到目前为止,我所尝试的: 用尽可能少的代码创建mysqli每秒22次插入 使用尽可能少的代码进行PDO每秒22次插入 将连接主机从localhost更改为127.0.

我正在测试一个我正在构建的系统的性能,它真的很慢,我不知道为什么或者它是否应该这么慢。我测试的是我可以对数据库进行多少次单次插入,每秒大约22次。这听起来真的很慢,当我尝试插入一个大型SQL查询时,我可以在大约0.5秒内插入30000条记录。在现实生活中,插入是由系统中的不同用户进行的,因此连接、发送查询、解析查询等开销始终存在。到目前为止,我所尝试的:

  • 用尽可能少的代码创建mysqli每秒22次插入
  • 使用尽可能少的代码进行PDO每秒22次插入
  • 将连接主机从localhost更改为127.0.0.1=每秒插入22次
  • 不带语句对象的mysqli,检查SQL注入=每秒22次插入
所以这里有点不对劲

系统规格:

  • 英特尔i5
  • 16千兆内存
  • 7200 rpm磁盘驱动器
软件:

  • 视窗10
  • XAMPP,与MariaDB相当新
  • 数据库引擎innoDB
我用于执行测试的代码:

$amountToInsert = 1000;
//$fakeData is an array with randomly generated emails 
$fakeData = getFakeData($amountToInsert); 
$db = new DatabaseHandler();
for ($i = 0; $i < $amountToInsert; $i++) {
    $db->insertUser($fakeUsers[$i]);
}
$db->closeConnection();
“用户”表有4列,结构如下:

  • id INT无符号主键
  • 电子邮件VARCHAR(60)
  • 公司id整型无符号索引
  • guid文本

我在这里不知所措,不知道下一步该去哪里。非常感谢您在正确方向上提供的任何帮助。

您的测试不是判断性能的好方法。为什么?因为你准备了1000次陈述。这不是准备好的语句应该被使用的方式。语句准备一次,不同的参数绑定多次。试试这个:

public function __construct() {
    $this->mDb = new mysqli($this->DBHOST, $this->DBUSERNAME
                          , $this->DBPASSWORD, $this->DBNAME
                          , $this->DBPORT);
    $this->isConnected = true;
    $queryString = 'INSERT INTO `users`(`email`, `company_id`) '
                    .'VALUES (?, 1)';
    $this->stmt_insert = $this->mDb->prepare($queryString);

}

而且,您将看到性能的巨大提升。总而言之,您的系统没有问题,只是测试不好

更新:

有一点是关于提前准备和重用已准备好的语句,而不是提供很大的帮助。我测试了一下,发现大约是5-10%

然而,有一些东西确实给了我们很大的推动。正在将自动提交关闭!。插入100条以前平均花费4.7秒的记录,现在平均时间降到<0.5秒

$con->autocommit(假)

/环路/
$con->commit()

正如评论中所解释的,应该归咎于InnoDB。默认情况下,此引擎过于谨慎,在返回成功消息之前,不会利用磁盘缓存来确保数据确实已写入磁盘。所以你基本上有两个选择

  • 大多数时候,你只是不喜欢确认的文字。因此,您可以通过将此mysql选项设置为零来配置mysql:

    innodb_flush_log_at_trx_commit = 0
    
    只要这样设置,您的InnoDB写入速度几乎与MyISAM一样快

  • 另一种选择是将所有写入内容包装到单个事务中。因为它只需要所有写入操作的一次确认,所以它的速度也是合理的


  • 当然,用多次插入只准备一次查询是明智的,但是与上面的问题相比,速度的提高可以忽略不计。因此,它既不能作为解释,也不能作为解决此类问题的补救措施。

    考虑到您的设置,每秒22次似乎是合理的。请记住,您执行的每一次
    commit
    都必须导致对磁盘的物理写入,不允许缓存。甚至可能多次写入元数据和其他内容。在一个事务中进行多次插入可以提高记录/秒,但如果这不是真实世界的用例场景,那么像这样进行基准测试将是愚蠢的。如果这是您的选项,请在此表中将引擎从InnoDB更改为MyISAM。由于它是用户表,字段不多,因此不需要频繁更新,因此不应该成为问题。插入会更快,但也有一些缺点。只有比较INSERTs perf结果才值得一试。如果在操作系统崩溃的情况下,您能够承受最后一秒的事务损失,那么my.ini中trx commit=0的innodb flush log就是您的朋友。如果您捕获到事务中的批插入,那么事务就是您的朋友。@JimmyB我只是好奇,您是否使用过mysql?@JimmyB正是。但是,这仍然是一个问题,你是否真的需要在这里进行交易,如果你不需要的话,预期的速度是多少。从技术上来说,你是对的,但说到期望值,22 wps太低了。然而,我攻击你是错误的,为此我道歉。你的贡献通常是完美的,但这一点是完全不正确的。在任何地方,多次执行带来的性能提升都是“巨大的”。1-2%如果你运气好的话。
    public function insertUser($user) {
        $this->stmt_insert->bind_param('s', $user);
        if ($this->stmt_insert->execute()) {
            return 1;
        } else {
            return 0;
        }
    }
    
    innodb_flush_log_at_trx_commit = 0