2016-11-10 170 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. 另一種選擇是將所有寫入操作封裝在單個事務中。由於它只需要所有寫入的單一確認,所以它也將很快合理。

當然,這只是理智與多個插件只有一次準備查詢,但相比上述問題的速度增益是微不足道的。所以它不算作解釋,也不算作這樣的的一個問題。