今天新開發的功能上線之后出現了查詢效率極其低下的問題,查詢日志后發現問題出在代碼內的大量的count()查詢上,最嚴重時一條簡單的count()查詢執行時間長達120多秒!
針對這個問題請教前輩后被告知原因:InnoDB引擎下的count()語句會在實時查詢表中的所有數據后返回總數所以效率較低,而MyISAM引擎則是直接返回表內存儲的行記錄信息所以效率較高。因為我本地的數據庫引擎為MyISAM而線上的阿里雲數據庫服務器引擎為InnoDB所以出現了這種本地環境與線上環境查詢效率差距極大的問題。
並且前輩也給出了指導意見:因為InnoDB引擎的主鍵索引通常為聚簇索引,為了保證效率可以新建一個輔助索引用於為count()查詢指定字段。經嘗試后使用新的輔助索引字段進行count()查詢效率確實大大提升。
這里附上查詢當前表引擎並判斷是使用主鍵字段還是使用輔助索引字段進行count()查詢的相關代碼。
框架使用的是ThinkPHP5,可以根據自己的狀況自行調整代碼。
function xmsb_getCountField($tableName) { $dataBase = config('database.database'); $tableStatus = Db::query("SHOW TABLE STATUS FROM `{$dataBase}` WHERE name = '{$tableName}'"); // 獲取表信息 $engine = strtolower($tableStatus[0]['Engine']); // 取得表引擎信息 // 取得主鍵字段 $pk = Db::getTableInfo($tableName, 'pk'); if(is_array($pk)) $pk = $pk[0]; // 若表引擎為InnoDB則判斷是否存在非主鍵索引 if($engine == 'innodb') { $indexs = Db::query("SHOW INDEX FROM {$tableName}"); $key = $pk; foreach($indexs as $index) { // 若存在非主鍵索引,則返回該索引對應的字段 if($index['Key_name'] != 'PRIMARY') { $key = $index['Column_name']; break; } } return $key; } else { // 非InnoDB引擎則直接返回主鍵字段 return $pk; } } $count = Db::name('數據表名') -> count(xmsb_getCountField('完整數據表名'));