1、背景
innodb引擎存儲int類型時使用big-endian, 而mysql使用litter-endian, 導緻一個問題是在兩個層之間拷貝int類型資料的時候必須用一個循環來處理,而不能直接memcpy。 在引擎層傳回資料量很大的情況下,很耗cpu。
在報表類的一些查詢中,會通路大量的資料。我們有個項目的一個查詢需要通路到1.4w個bigint,這個時候cpu的消耗就展現出來了。
2、相關代碼
目前使用的轉換代碼就是使用循環。
row_sel_field_store_in_mysql_format這個函數的作用是把資料從innodb格式轉成mysql格式,
如下:
ptr = dest + len;
for (;;) {
ptr--;
*ptr = *data;
if (ptr == dest) {
break;
}
data++;
這裡如果是bigint就需要循環8次。
反過來的轉換代碼在row_mysql_store_col_in_innobase_format,也是類似的需要一個循環。
3、改進和效果
這一坨循環,o3編譯以後的彙編代碼下,如果是bigint,需要40條指令。而顯然我們使用的時候,int和bigint會很多。
是以考慮當len=4或8的時候,使用bswap和bswapq實作。
修改後再用oprofile觀察上面說到的一個統計查詢壓力下的結果,發現row_sel_field_store_in_mysql_format這個函數cpu占用率從50%下降到44%.
db的多數情況下壓力還是在io,是以這個改進的效果需要在特定場景下才能展現。 最近跟oracle innodb工程師讨論的時候了解到會有一些專門針對減少彙編結果做的優化,就湊熱鬧把這個提了。
patch内容: http://bugs.mysql.com/file.php?id=18018&text=1 基于5.5.22