2014-12-04 77 views
5

最近我的任務是進行一些速度檢查,以便我可以判斷使用php/php-cli或C++將特定數量的行插入數據庫的速度是否更快。MySQL的插入速度比PHP更快,這是預期的嗎?

在我們開始之前,讓我告訴你一些細節,讓一切都清楚了:

  • PHP的一部分是通過運行Apache,在瀏覽器中直接提出要求。
  • 正在運行的硬盤驅動器測試是SSD驅動器。我猜在普通硬盤中事情會變慢。機器本身沒什麼特別的,六歲左右。
  • 所有插入操作都是通過準備好的語句完成的。我們使用php上的mysqli和mysqlcppconcon(由Oracle提供的mysql C++連接器)。
  • 所有插入都按條目輸入。我知道我們可以堆疊它們,但是我們正在測試。
  • 時間通過microtime在php中顯示,並通過C++頭文件顯示。
  • 當然,代碼本身並不等同。稍後更多。
  • 所有文本都是UTF-8。那裏有俄羅斯,中國,阿拉伯,西班牙,英國和各種瘋狂的東西。 mysql表格在utf8_4mb中。
  • C++代碼的數字是使用g ++編譯的std :: vector和-O2 levels的結果(向量優於maps,unordered_maps和std :: arrays)。

所以,這是過程:

  • 連接到數據庫。
  • 用N行打開一個文本文件。
  • 閱讀文件的一行。
  • 拆分分隔符上的行。
  • 使用分割線的某些部分來獲取插入值(例如,0,1和3索引)。
  • 將這些零件發送到準備好的語句以插入它們。
  • 重複,直到完全讀取文件。

兩個代碼的工作方式與預期完全相同。下面是導致數字:

PHP:

  • 5000個條目:1.42 - 1.27秒。
  • 20000條目:5.53-6.18秒。
  • 50000條目:14.43-15.69秒。

C++:

  • 5000個條目:1.78 - 1.81秒。
  • 20000條目:7.19 - 7.22秒。
  • 50000條目:18.52-18.84秒

php優於C++,因爲文件中的行數增加......起初,我懷疑行分裂函數:在PHP中的分裂是用「爆炸」完成的。該算法與C++一樣天真......容器通過引用傳遞,其內容隨時更改。該容器僅被遍歷一次。我確保容器「保留()」所有必要的空間(記住,我最終選擇向量),這是固定的。容器在主函數上創建,然後通過代碼通過引用傳遞。它永遠不會被清空或調整大小:只有其內容發生變化。

template<typename container> void explode(const std::string& p_string, const char p_delimiter, container& p_result) 
{ 
    auto it=p_result.begin(); 
    std::string::const_iterator beg=p_string.begin(), end=p_string.end(); 
    std::string temp; 

    while(beg < end) 
    { 
     if((*beg)==p_delimiter) 
     { 
      *(it)=temp; 
      ++it; 
      temp=""; 
     } 
     else 
     { 
      temp+=*beg; 
     } 

     ++beg; 
    } 

    *(it)=temp; 
} 

如前所述,執行的任務是等效的,但生成它的代碼不是。 C++代碼具有通常的try-catch塊來控制mysql的交互。至於其餘部分,主循環一直運行到EOF到達,並且每次迭代檢查插入是否失敗(無論是在C++還是php中)。

我已經看到C++在處理文件和它們的內容方面大大優於php,所以我期望在這裏適用。不知何故,我懷疑分裂算法,但也許它只是數據庫連接器速度較慢(仍然,當我禁用數據庫交互PHP仍然處理更快)或我的代碼是sub par ...

至於分析, gprof的吐出了這一點,關於C++代碼:

Each sample counts as 0.01 seconds. 
    % cumulative self    self  total   
time seconds seconds calls ns/call ns/call name  
60.00  0.03  0.03 50000 600.00 600.00 void anc_str::explotar_cadena<std::vector<std::string, std::allocator<std::string> > >(std::string const&, char, std::vector<std::string, std::allocator<std::string> >&) 
40.00  0.05  0.02        insertar(sql::PreparedStatement*, std::string const&, std::vector<std::string, std::allocator<std::string> >&) 
    0.00  0.05  0.00  1  0.00  0.00 _GLOBAL__sub_I__ZN7anc_str21obtener_linea_archivoERSt14basic_ifstreamIcSt11char_traitsIcEE 

其中「explotar_cadena」是「爆炸」和「insertar」是「拆分此行並設置事先準備好的聲明瞭」。正如你所看到的,有60%的時間花在那裏(並不令人驚訝......它運行了50000次,並且做了這個瘋狂的分裂事情)。 「obtener_linea_archivo」只是「請將下一行轉儲到字符串中」。

沒有MySQL的相互作用(只是加載文件,讀取線和分割他們)我得到這些測量:

PHP

  • 5000個條目:0.019 - 0.036秒。
  • 20000個條目:0.09-0.10秒。
  • 50000個條目:0.14-0.17秒

C++

  • 5000個條目:0.07 - 0.10秒。
  • 20000個條目:0.25 - 0.26秒。
  • 50000個條目:0.49-0.55秒。

好吧,這兩個時代都很好,現實生活中還很難察覺,我很驚訝...所以這裏的問題是:我應該期待這個嗎?有經驗的人願意伸出援助之手嗎?

在此先感謝。

編輯:這裏是一個包含輸入文件,C++代碼和php代碼的精簡版的快速鏈接[http://www.datafilehost.com/d/d31034d6]。注意,沒有sql交互:只有文件打開,字符串分割和時間測量。請原諒匆忙完成的屠殺代碼和半西班牙語評論和變量名稱。另外,請注意上面的gprof結果:我不是專家,但我認爲我們試圖找到一種更好的分割字符串的方法。

+0

你能否認爲用[Very Sleepy](http://www.codersnotes.com/sleepy)來測試你的C++程序並在這裏添加結果。 – 2014-12-04 10:29:24

+0

不是窗戶的人在這裏,對不起...我試過gprof。將編輯帖子以反映這一點。 – 2014-12-04 10:35:51

+1

從代碼中刪除定時器,使用控制檯上的系統時間命令來獲取測量結果。您不包括PHP的啓動和關閉時間,結果偏差。 – 2014-12-04 10:57:23

回答

1

它的某些部分可能與每種語言中使用的驅動程序/接口有關。例如,在PHP/MySQL中,您可能會發現mysqli比mysql更快,這比PDO快。這是因爲圖書館逐漸更抽象(或更少維護)。您可以嘗試在數據庫服務器上自行分析查詢,以查看執行時間是否有任何差異。然而,正如其他評論者指出的那樣,可能還會有更多的事情發生。

+0

非常感謝您的回答。我想我可以假設實現本身有更多的層次,因此速度更慢。儘管如此,沒有任何數據庫交互,我用PHP獲得了更好的數字(正如你在編輯的問題中看到的那樣)。如前所述,C++代碼似乎比簡單的php代碼生成更多的指令。 – 2014-12-09 08:02:07