數據庫的瓶頸經常出現在查詢 語句中,當出現這樣的問題時,我們一般的步驟是查看是否運用了正確的 索引,
這個可以通過explain sql statement來查看,找到對應的字段,合理的索引將會增加你呃數據的訪問速度,但
任何事情都有一個度,如果索引太多,會在插入時要維護更多的索引,這也將是一個大的開銷,但具體怎樣才
合適呢,歡迎大神來討論,這個我不再行,不過一般一個表中有主鍵活唯一鍵,再弄幾個的話應該不是問題。
1.1、mysql是如何執行where字句的
這些語句通常很快:
SELECT COUNT(*) FROM tbl_name;
SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;
SELECT MAX(key_part2) FROM tbl_name
WHERE key_part1=constant;
SELECT ... FROM tbl_name
ORDER BY key_part1,key_part2,... LIMIT 10;
SELECT ... FROM tbl_name
ORDER BY key_part1 DESC, key_part2 DESC, ... LIMIT 10;
但前提是這些訪問的字段部分都有索引,因爲如min(),max(),order by 這些語句會用到排序的,但如果之前已經
建立好了索引,那麼讀的時候就通過二分的方法來 遍歷Btree,這速度很快,如果沒有索引,這個只能全表掃描,
速度會很慢的,對於第一個語句,在MyISAM和MEMORY存儲引擎的表,可以直接讀取這個值,因爲這個有這
兩個存儲引擎有相應的計數器來維護數據,但innodb則必須全表掃描才能得到結果,截圖如下:
mysql> explain select count(*) from b_order\G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: b_order
type: index
possible_keys: NULL
key: status
key_len: 1
ref: NULL
rows: 274146
Extra: Using index
1 row in set (0.01 sec)
當使用該語句時,掃描了所有的行,但我們是用主鍵索引的,這個速度還比較快
1.2,mysql內部優化策略
1,count(*) 這個之前已經說了
2,mysql和oracle都是採用邊讀數據邊判斷數據,滿足數據就發送到客戶端,滿足sql要求就結束查詢,所以
謹記一下:如果對你的數據不是要求全部的行,比如只要滿足當前sql的幾行數據,最好加上limit語句,這
樣會讓數據庫提前結束查詢,少佔內存,少讀取數據,少網絡帶寬傳輸
3,HAVING語句如果在沒有使用聚合函數如count(), min()等,沒有group by語句時,將合併到where字句中
4,所有的常量表優先於其他表進行讀取,一個常量表的定義爲:
1,一個空表或者只有一行的表
2,如果一下表使用where字句時,用到了一個非空主鍵或唯一索引,並且這個搜索的是一個常量表達式
3,還有一種情況,就是join的一個表就只有幾行,是否會優先讀(可以試試)
如下面的語句:
SELECT * FROM t WHERE primary_key=1;
SELECT * FROM t1,t2
WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
解釋:1,第一個是一個小表,只有一行
2,這個先查他t1,因爲其返回的數據只有一行
5,這裏說一下join的策略:數據庫沒有那麼智能,能一下就能找到好的join順序來執行,他會把所有可能的
join順序都試一下,調用存儲引擎的api來評估代價,然後選擇最小的代價進行執行,所以,我們寫的表
的順序,對優化器來說,是沒有關係的
6,在同時使用group by 和order by時,如果字段都來自同一個表,將優先join該表
7,對於需要排序的數據,如果你在explain中查看到使用了文件排序,但你確定這個數據集不是很大的話,
可以在sql中指定SQL_SMALL_RESULT來使用內存臨時表排序,這樣會快些,方法爲:
select sql_small_result * from table_name;
8,MySQL有可能查詢結果從索引中獲得,但這個一般都是數值
9,HAVING語句是最後過濾結果的條件