不少時候,咱們在mysql中建立了索引,可是某些查詢仍是很慢,根本就沒有使用到索引!通常來講,多是某些字段沒有建立索引,或者是組合索引中字段的順序與查詢語句中字段的順序不符。
看下面的例子:
假設有一張訂單表(orders),包含order_id和product_id二個字段。
一共有31條數據。符合下面語句的數據有5條。執行下面的sql語句:html
1
2
3
|
select product_id
from orders
where order_id in (
123
,
312
,
223
,
132
,
224
);
|
這條語句要mysql去根據order_id進行搜索,而後返回匹配記錄中的product_id。因此組合索引應該按照如下的順序建立:java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
create index orderid_productid on orders(order_id, product_id)
mysql> explain select product_id from orders where order_id in (
123
,
312
,
223
,
132
,
224
) \G
***************************
1
. row ***************************
id:
1
select_type: SIMPLE
table: orders
type: range
possible_keys: orderid_productid
key: orderid_productid
key_len:
5
ref: NULL
rows:
5
Extra: Using where; Using index
1
row in set (
0.00
sec)
|
能夠看到,這個組合索引被用到了,掃描的範圍也很小,只有5行。若是把組合索引的順序換成product_id, order_id的話,mysql就會去索引中搜索 *123 *312 *223 *132 *224,必然會有些慢了。mysql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
mysql> create index orderid_productid on orders(product_id, order_id);
Query OK,
31
rows affected (
0.01
sec)
Records:
31
Duplicates:
0
Warnings:
0
mysql> explain select product_id from orders where order_id in (
123
,
312
,
223
,
132
,
224
) \G
***************************
1
. row ***************************
id:
1
select_type: SIMPLE
table: orders
type: index
possible_keys: NULL
key: orderid_productid
key_len:
10
ref: NULL
rows:
31
Extra: Using where; Using index
1
row in set (
0.00
sec)
|
此次索引搜索的性能顯然不能和上次相比了。rows:31,個人表中一共就31條數據。索引被使用部分的長度:key_len:10,比上一次的key_len:5多了一倍。不知道是這樣在索引裏面查找速度快,仍是直接去全表掃描更快呢?sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
mysql> alter table orders add modify_a
char
(
255
)
default
'aaa'
;
Query OK,
31
rows affected (
0.01
sec)
Records:
31
Duplicates:
0
Warnings:
0
mysql>
mysql>
mysql> explain select modify_a from orders where order_id in (
123
,
312
,
223
,
132
,
224
) \G
***************************
1
. row ***************************
id:
1
select_type: SIMPLE
table: orders
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows:
31
Extra: Using where
1
row in set (
0.00
sec)
|
這樣就不會用到索引了。 剛纔是由於select的product_id與where中的order_id都在索引裏面的。數據庫
爲何要建立組合索引呢?這麼簡單的狀況直接建立一個order_id的索引不就好了嗎?果只有一個order_id索引,沒什麼問題,會用到這個索引,而後mysql要去磁盤上的表裏面取到product_id。若是有組合索引的話,mysql能夠徹底從索引中取到product_id,速度天然會快。再多說幾句組合索引的最左優先原則:
組合索引的第一個字段必須出如今查詢組句中,這個索引纔會被用到。果有一個組合索引(col_a,col_b,col_c),下面的狀況都會用到這個索引:
數據庫設計
1
2
3
4
|
col_a =
"some value"
;
col_a =
"some value"
and col_b =
"some value"
;
col_a =
"some value"
and col_b =
"some value"
and col_c =
"some value"
;
col_b =
"some value"
and col_a =
"some value"
and col_c =
"some value"
;
|
對於最後一條語句,mysql會自動優化成第三條的樣子~~。下面的狀況就不會用到索引:post
1
2
|
col_b =
"aaaaaa"
;
col_b =
"aaaa"
and col_c =
"cccccc"
;
|
列轉自:http://hi.baidu.com/liuzhiqun/blog/item/4957bcb1aed1b5590823023c.html性能
經過實例理解單列索引、多列索引以及最左前綴原則。實例:如今咱們想查出知足如下條件的用戶id:
mysql>SELECT `uid` FROM people WHERE lname`='Liu' AND `fname`='Zhiqun' AND `age`=26
由於咱們不想掃描整表,故考慮用索引。
單列索引:
ALTER TABLE people ADD INDEX lname (lname);
將lname列建索引,這樣就把範圍限制在lname='Liu'的結果集1上,以後掃描結果集1,產生知足fname='Zhiqun'的結果集2,再掃描結果集2,找到 age=26的結果集3,即最終結果。
由 於創建了lname列的索引,與執行表的徹底掃描相比,效率提升了不少,但咱們要求掃描的記錄數量仍舊遠遠超過了實際所需 要的。雖然咱們能夠刪除lname列上的索引,再建立fname或者age 列的索引,可是,不論在哪一個列上建立索引搜索效率仍舊類似。
2.多列索引:
ALTER TABLE people ADD INDEX lname_fname_age (lame,fname,age);
爲了提升搜索效率,咱們須要考慮運用多列索引,因爲索引文件以B-Tree格式保存,因此咱們不用掃描任何記錄,便可獲得最終結果。
注:在mysql中執行查詢時,只能使用一個索引,若是咱們在lname,fname,age上分別建索引,執行查詢時,只能使用一個索引,mysql會選擇一個最嚴格(得到結果集記錄數最少)的索引。
3.最左前綴:顧名思義,就是最左優先,上例中咱們建立了lname_fname_age多列索引,至關於建立了(lname)單列索引,(lname,fname)組合索引以及(lname,fname,age)組合索引。
注:在建立多列索引時,要根據業務需求,where子句中使用最頻繁的一列放在最左邊。大數據
創建索引的時機優化
到這裏咱們已經學會了創建索引,那麼咱們須要在什麼狀況下創建索引呢?通常來講,在WHERE和JOIN中出現的列須要創建索引,但也不徹底如此,由於MySQL只對<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE纔會使用索引。例如:
1
|
SELECT t.Name FROM mytable t LEFT JOIN mytable m ON t.Name=m.username WHERE m.age=
20
AND m.city=
'鄭州'
|
此時就須要對city和age創建索引,因爲mytable表的userame也出如今了JOIN子句中,也有對它創建索引的必要。
剛纔提到只有某些時候的LIKE才需創建索引。由於在以通配符%和_開頭做查詢時,MySQL不會使用索引。例以下句會使用索引:
1
|
SELECT * FROM mytable WHERE username like
'admin%'
|
下句就不會使用:
1
|
SELECT * FROM mytable WHEREt Name like
'%admin'
|
所以,在使用LIKE時應注意以上的區別。
索引的不足之處
上面都在說使用索引的好處,但過多的使用索引將會形成濫用。所以索引也會有它的缺點:
使用索引的注意事項
使用索引時,有如下一些技巧和注意事項:
只要列中包含有NULL值都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此複合索引就是無效的。因此咱們在數據庫設計時不要讓字段的默認值爲NULL。
對串列進行索引,若是可能應該指定一個前綴長度。例如,若是有一個CHAR(255)的列,若是在前10個或20個字符內,多數值是唯一的,那麼就不要對整個列進行索引。短索引不只能夠提升查詢速度並且能夠節省磁盤空間和I/O操做。
MySQL查詢只使用一個索引,所以若是where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。所以數據庫默認排序能夠符合要求的狀況下不要使用排序操做;儘可能不要包含多個列的排序,若是須要最好給這些列建立複合索引。
通常狀況下不鼓勵使用like操做,若是非使用不可,如何使用也是一個問題。like 「%aaa%」 不會使用索引而like 「aaa%」可使用索引。
select * from users where YEAR(adddate)<2007;
將在每一個行上進行運算,這將致使索引失效而進行全表掃描,所以咱們能夠改爲
select * from users where adddate<‘2007-01-01’;