首先我們在日志文件中查到下面語句的執行比較慢超過秒了
# Query_time: Lock_time: Rows_sent: Rows_examined:
select * from TSK_TASK WHERE STATUS_ID = and MON_TIME >= and MON_TIME < ;
原來在條記錄中要查出符合條件的條記錄那當然慢了趕緊用EXPLAIN語句看一下索引使用情況吧
+++++
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+++++
| | SIMPLE | TSK_TASK | ref | FK_task_status_id_TO_SYS_HIER_INFOTSK_TASK_KEY_MON_TIME | FK_task_status_id_TO_SYS_HIER_INFO | | const | | Using where |
+++++
可以看出有兩個索引可用FK_task_status_id_TO_SYS_HIER_INFOTSK_TASK_KEY_MON_TIME而最終執行語句時采用了STATUS_ID上的外鍵索引
再看一下TSK_TASK表的索引情況吧
++
| Table | Key_name | Column_name | Cardinality |
+++
| TSK_TASK | PRIMARY | ID | |
| TSK_TASK | FK_task_status_id_TO_SYS_HIER_INFO | STATUS_ID | |
| TSK_TASK | TSK_TASK_KEY_MON_TIME | MON_TIME | |
++
在Oracle或其他關系數據庫下WHERE條件中的字段順序對索引的選擇起著很重要的作用我們調整一下字段順序把STATUS_ID放在後面再EXPLAIN一下
EXPLAIN select * from TSK_TASK WHERE MON_TIME >= and MON_TIME < and STATUS_ID = ;
但是沒什麼效果MySQL還是選用系統建立的STATUS_ID外鍵索引
仔細分析一下看來Cardinality屬性(即索引中的唯一值的個數)對索引的選擇起了極其重要的作用MySQL選擇了索引值唯一值個數小的那個索引作為整條語句的索引
針對這條語句如果使用FK_task_status_id_TO_SYS_HIER_INFO做索引而TSK_TASK表中存放很多天數據的話那掃描的記錄數會很多速度較慢可以有以下幾個優化方案
如果一天的任務數不多的話我們刪除索引FK_task_status_id_TO_SYS_HIER_INFO那MySQL會使用索引TSK_TASK_KEY_MON_TIME然後在該天的數據中在掃描STATUS_ID為的記錄那速度也不慢
如果一天的任務數多的話我們需刪除索引FK_task_status_id_TO_SYS_HIER_INFO和TSK_TASK_KEY_MON_TIME然後再建立STATUS_IDMON_TIME的聯合索引這樣效率肯定會很高
因此建議對那些記錄數多的表建議不要使用外鍵以避免造成性能效率的嚴重降低
盡量控制每張表的記錄數
當一張表的記錄數很大時管理和維護就會很麻煩如索引維護就會占用很長時間從而會給系統的正常運行造成很大的干擾
對隨時間推移數據量不斷增長的表我們可以根據時間來區分實時數據和歷史數據可以使用後台服務程序定期移動實時表中的數據到歷史表中從而控制實時表的 記錄數提高查詢和操作效率但注意每次移動的時間要足夠短不要影響正常程序的數據寫入如果占用時間太長可能會造成死鎖問題
數據散列(partition)策略
當客戶數達到一定規模後單個數據庫將無法支撐更高的並發訪問此時可以考慮把客戶數據散列(partition)到多個數據庫中以分擔負載提高系統的整體性能與效率
[] []
From:http://tw.wingwit.com/Article/program/MySQL/201311/29599.html