2016-11-10 148 views
1

我正在尝试使用我正在构建的系统的性能,而且速度很慢,我不知道为什么或者它应该如此缓慢。我测试的是我可以对数据库做多少次INSERT,每秒钟可以达到22次。这听起来非常慢,当我尝试插入时,我可以在大约0.5秒内插入30000条记录,这是一个singel大型SQL查询。在现实生活中,插入是由系统中的不同用户创建的,因此连接,发送查询,解析查询等的开销总是在那里。我到目前为止所尝试的:性能下降MySql

  • mysqli尽可能少的代码。 = 22每秒插入
  • PDO尽可能少的代码。 =每秒
  • 22 INSERT从本地主机每秒
  • 的mysqli 127.0.0.1 = 22 INSERT更改连接的主机没有Statement对象和检查SQL注入=每秒

因此,一些接缝22 INSERT在这里是错误的。

系统规格:

  • 英特尔酷睿i5
  • 16演出RAM
  • 7200转盘驱动

软件:

  • 的Windows 10
  • XAMP P,与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(); 

调用数据库类:

class DatabaseHandler { 
    private $DBHOST = 'localhost'; 
    private $DBUSERNAME = 'username'; 
    private $DBPASSWORD = 'password'; 
    private $DBNAME = 'dbname'; 
    private $DBPORT = 3306; 

    private $mDb; 

    private $isConnected = false; 

    public function __construct() { 
     $this->mDb = new mysqli($this->DBHOST, $this->DBUSERNAME 
           , $this->DBPASSWORD, $this->DBNAME 
           , $this->DBPORT); 
     $this->isConnected = true; 
    } 

    public function closeConnection() { 
     if ($this->isConnected) { 
      $threadId = $this->mDb->thread_id; 
      $this->mDb->kill($threadId); 
      $this->mDb->close(); 
      $this->isConnected = false; 
     } 
    } 

    public function insertUser($user) { 
     $this->mDb->autocommit(true); 
     $queryString = 'INSERT INTO `users`(`email`, `company_id`) ' 
         .'VALUES (?, 1)'; 
     $stmt = $this->mDb->prepare($queryString); 
     $stmt->bind_param('s', $user); 
     if ($stmt->execute()) { 
      $stmt->close(); 
      return 1; 
     } else { 
      $stmt->close(); 
      return 0; 
     } 
    } 
} 

“用户” 表中有4列结构如下:

  • id INT无符号主键
  • 电子邮件VARCHAR(60)
  • COMPANY_ID INT无符号INDEX
  • GUID TEXT

我在这里损失真的不知道在哪里旁边看。任何帮助正确的方向将非常感激。

+1

给定你的设置,每秒22个似乎是合理的。请记住,您执行的每个'commit'都必须*导致写入磁盘,物理,不允许缓存。可能甚至多次写入元数据和东西。在一次事务中执行多次插入会提高每秒的记录次数,但如果这不是真实世界的用例场景,那么基准测试就是这样。 – JimmyB

+0

如果这是您的选项,请在此表上将引擎从* InnoDB *更改为* MyISAM *。即使它是没有太多字段的用户表,因此不需要频繁的UPDATE,它不应该是一个问题。插入会更快,但有一些缺点。只有比较你的INSERT性能结果值得一试。 –

+0

如果您在操作系统崩溃的情况下可以承担松散最后一秒的交易,那么my.ini中的innodb-flush-log-at-trx-commit = 0是您的朋友。如果您将批量插入事务处理,交易是您的朋友。 –

回答

0

你的测试并不是判断性能的好方法。为什么,因为你正在准备一个声明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); 

} 

public function insertUser($user) { 
    $this->stmt_insert->bind_param('s', $user); 
    if ($this->stmt_insert->execute()) { 
     return 1; 
    } else { 
     return 0; 
    } 
} 

而且,你将看到性能的巨大提升。所以回顾一下,你的系统没有问题,只是测试不好。

更新:

Your Common Sense有一个关于提前准备和重用不给一个大的提升准备的语句点。我测试并发现它约为5-10%然而,有些东西确实给予了很大的提升。将Autocommit关闭!插入先前平均需要4.7秒的100条记录平均下降到< 0.5秒!

$ con> autocommit(false);

/loop/ $ con> commit();

+0

你的贡献通常是完美的,但这是完全不合时宜的。无论多执行一次性能提升是“巨大的”。如果你幸运的话,1-2%。 –

1

就像它在评论中解释的那样,这是InnoDB的责任。默认情况下,此引擎过于谨慎,不会利用磁盘缓存,以确保数据确实已写入磁盘,然后再返回成功消息。所以你基本上有两种选择。

  1. 大多数时候你只是不关心确认的写。所以,你可以通过这个MySQL选项设置为零配置MySQL:只要它是这样设置的

    innodb_flush_log_at_trx_commit = 0 
    

    ,你写的InnoDB将几乎一样快的MyISAM。

  2. 另一种选择是将所有写入操作封装在单个事务中。由于它只需要所有写入的单一确认,所以它也将很快合理。

当然,这只是理智与多个插件只有一次准备查询,但相比上述问题的速度增益是微不足道的。所以它不算作解释,也不算作这样的的一个问题。