2016-11-10 16 views
1

私は構築しているシステムのパフォーマンスを試していますが、それは本当に遅いですし、なぜそれが遅いのかわかりません。私がテストしているのは、データベースにできるINSERTの数と、1秒あたり約22回です。それは本当に遅く聞こえて、私は挿入物を私は約0.5秒で30000のレコードを挿入することができる私は大きなSQLクエリをsingelをしようとしたとき。現実には、挿入はシステム内のさまざまなユーザーによって行われるため、接続、クエリの送信、クエリの解析などのオーバーヘッドが常に存在します。これまでに試したこと:遅い性能MySql

  • mysqliにはできるだけコードを入れないでください。 = 22 INSERT per second
  • できるだけコードを小さくしたPDO。 = 22 127.0.0.1へのローカルホストからの接続ホストを変更
  • 毎秒INSERT =文オブジェクトなし
  • 秒mysqliのあたり22 INSERTおよびSQLインジェクションのチェック=

毎秒22 INSERTだから、何かの縫い目ここで間違っている。

システムスペック:

  • インテルのi5
  • 16ギグラム
  • 7200 rpmのディスクドライブ

ソフトウェア:

  • のWindows 10
  • XAMP P、まったく新しいMariaDBで
  • DBエンジンinnoDB。

Iテストを行うために使用されるコード:

$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

設定を考えると、1秒あたり22個は妥当と思われます。あなたが実行するすべての 'コミット 'は、ディスクへの書き込み、物理的な、キャッシングが許可されていなければならないことを忘れないでください。おそらくメタデータやもののための複数の書き込み。 1回のトランザクションで多数の挿入を行うと、1秒あたりのレコード数が増えますが、それが実際の使用例のシナリオではない場合、そのようなベンチマークは愚かでしょう。 – JimmyB

+0

これがオプションの場合は、この表のエンジンを* InnoDB *から* MyISAM *に変更してください。多くのフィールドを持たないユーザーテーブルであり、頻繁な更新が必要ない場合は、問題ではありません。 INSERTは地獄速くなりますが、いくつかの欠点があります。あなたのINSERTを比較するためだけにperf結果を試してみる価値があります。 –

+0

OSクラッシュの場合にトランザクションの最後の1分を失うことができれば、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%であることを発見しました。

しかし、大きなブーストを与えるものがあります。自動コミットをオフにする!これまで平均して約4.7秒かかっていた100レコードを挿入すると平均で<になりました!

$ con-> autocommit(false);

/ループ/ $ con-> commit();

+0

あなたの貢献は、通常完璧ですが、これは完全にオフラインです。マルチプル実行からのパフォーマンスの向上は "巨大"です。あなたが運が良ければ1-2%。 –

1

Commentsで説明したように、それはInnoDBのせいです。デフォルトでは、このエンジンはあまりにも慎重であり、ディスクキャッシュを使用せず、成功メッセージを返す前にディスクに実際にデータが書き込まれていることを確認します。基本的に2つの選択肢があります。

  1. ほとんどの場合、確認済みの書き込みは気にしません。だから、あなたがゼロにこのmysqlのオプションを設定することで、MySQLを設定することができます。

    innodb_flush_log_at_trx_commit = 0 
    

    限り、それがこのように設定していますように、あなたのInnoDBは、ほぼ同じ速MyISAMのようになります書き込みます。

  2. もう1つの方法は、すべての書き込みを1回のトランザクションでラッピングすることです。それはすべての書き込みからの単一の確認だけを必要とするので、それも妥当な速さです。

もちろん、複数の挿入で1回だけクエリを準備するのは正気ですが、上記の問題に比べて速度の向上はごくわずかです。したがって、それはのような説明でも是正措置としてもカウントされません。の問題です。