本文中介紹的系統(tǒng)優(yōu)化,主要針對前端和后臺這兩方面(后臺方面主要對sql語句和數(shù)據(jù)存儲進(jìn)行了優(yōu)化),下文中我們將介紹一些優(yōu)化技巧和經(jīng)驗。
技巧:
1. 如何查出效率低的語句?
在mysql下,在啟動參數(shù)中設(shè)置 --log-slow-queries=[文件名],就可以在指定的日志文件中記錄執(zhí)行時間超過long_query_time(缺省為10秒)的sql語句。你也可以在啟動配置文件中修改long query的時間,如:
# set long query time to 8 seconds
long_query_time=8
2. 如何查詢某表的索引?
可使用show index語句,如:
show index from [表名]
3. 如何查詢某條語句的索引使用情況?
可用explain語句來看一下某條select語句的索引使用情況。如果是update或delete語句,需要先轉(zhuǎn)換為select語句。 
4. 如何把導(dǎo)出innodb引擎的內(nèi)容到錯誤日志文件中? 
我們可以使用show innodb status命令來查看innodb引擎的很多有用的信息,如當(dāng)前進(jìn)程、事務(wù)、外鍵錯誤、死鎖問題和其它一些統(tǒng)計數(shù)據(jù)。如何讓該信息能記錄在日志文件中 呢?只要使用如下語句創(chuàng)建innodb_monitor表,mysql就會每15秒鐘把該系統(tǒng)寫入到錯誤日志文件中:
create table innodb_monitor (a int) engine=innodb;
如果你不再需要導(dǎo)出到錯誤日志文件,只要刪除該表即可:
drop table innodb_monitor;
5. 如何定期刪除龐大的日志文件?
只要在啟動配置文件中設(shè)置日志過期時間即可:
expire_logs_days=10
注意事項:
1. 重點關(guān)注索引
下面以表tsk_task表為例說明sql語句優(yōu)化過程。tsk_task表用于保存系統(tǒng)監(jiān)測任務(wù),相關(guān)字段及索引如下:
id:主鍵;
mon_time:監(jiān)測時間;建了索引;
status_id:任務(wù)狀態(tài);與sys_hier_info.id建立了外鍵關(guān)系。
注mysql自動會為外鍵建立索引,在本次優(yōu)化過程中,發(fā)現(xiàn)這些自動建立的外鍵索引會對sql語句的效率產(chǎn)生不必要的干擾,需要特別注意!
首先,我們在日志文件中查到下面語句的執(zhí)行比較慢,超過10秒了:
# query_time: 18 lock_time: 0 rows_sent: 295 rows_examined: 88143
select * from tsk_task where status_id = 1064 and mon_time >= '2007-11-22' and mon_time < '2007-11-23';
原來在88143條記錄中要查出符合條件的295條記錄,那當(dāng)然慢了。趕緊用explain語句看一下索引使用情況吧:
+----+-------------+----------+------+----------
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | extra |
+----+-------------+----------+------+-----------
| 1 | simple | tsk_task | ref | fk_task_status_id_to_sys_hier_info,tsk_task_key_mon_time | fk_task_status_id_to_sys_hier_info | 9 | const | 276168 | using where |
+----+-------------+----------+------+-----------
可以看出,有兩個索引可用fk_task_status_id_to_sys_hier_info,tsk_task_key_mon_time,而最終執(zhí)行語句時采用了status_id上的外鍵索引。
再看一下tsk_task表的索引情況吧:
+----------+------------------------------------
| table | key_name | column_name | cardinality |
+----------+------------+-----------------------
| tsk_task | primary | id | 999149 |
| tsk_task | fk_task_status_id_to_sys_hier_info | status_id | 16 |
| tsk_task | tsk_task_key_mon_time | mon_time | 13502 |
+----------+------------------------------------
在oracle或其他關(guān)系數(shù)據(jù)庫下,where條件中的字段順序?qū)λ饕倪x擇起著很重要的作用。我們調(diào)整一下字段順序,把status_id放在后面,再explain一下:
explain select * from tsk_task where mon_time >= '2007-11-22' and mon_time < '2007-11-23' and status_id = 1064;
但是沒什么效果,mysql還是選用系統(tǒng)建立的status_id外鍵索引。
仔細(xì)分析一下,看來cardinality屬性(即索引中的唯一值的個數(shù))對索引的選擇起了極其重要的作用,mysql選擇了索引值唯一值個數(shù)小的那個索引作為整條語句的索引。
針對這條語句,如果使用fk_task_status_id_to_sys_hier_info做索引,而tsk_task表中存放很多天數(shù)據(jù)的話,那掃描的記錄數(shù)會很多,速度較慢。可以有以下幾個優(yōu)化方案:
如果一天的任務(wù)數(shù)不多的話,我們刪除索引fk_task_status_id_to_sys_hier_info,那mysql會使用索引tsk_task_key_mon_time,然后在該天的數(shù)據(jù)中在掃描status_id為1064的記錄,那速度也不慢;
如果一天的任務(wù)數(shù)多的話,我們需刪除索引fk_task_status_id_to_sys_hier_info和tsk_task_key_mon_time,然后再建立status_id,mon_time的聯(lián)合索引,這樣效率肯定會很高。
因此建議,對那些記錄數(shù)多的表,建議不要使用外鍵,以避免造成性能效率的嚴(yán)重降低。
2. 盡量控制每張表的記錄數(shù)
當(dāng)一張表的記錄數(shù)很大時,管理和維護(hù)就會很麻煩,如索引維護(hù)就會占用很長時間,從而會給系統(tǒng)的正常運行造成很大的干擾。
對隨時間推移數(shù)據(jù)量不斷增長的表,我們可以根據(jù)時間來區(qū)分實時數(shù)據(jù)和歷史數(shù)據(jù),可以使用后臺服務(wù)程序定期移動實時表中的數(shù)據(jù)到歷史表中,從而控制實時表的 記錄數(shù),提高查詢和操作效率。但注意每次移動的時間要足夠短,不要影響正常程序的數(shù)據(jù)寫入。如果占用時間太長,可能會造成死鎖問題。
3. 數(shù)據(jù)散列(partition)策略
當(dāng)客戶數(shù)達(dá)到一定規(guī)模后,單個數(shù)據(jù)庫將無法支撐更高的并發(fā)訪問,此時可以考慮把客戶數(shù)據(jù)散列(partition)到多個數(shù)據(jù)庫中,以分擔(dān)負(fù)載,提高系統(tǒng)的整體性能與效率。
新聞熱點
疑難解答
圖片精選