order by 不走索引的思考
今天早上檢視網站,發現非常慢!進linux 用top檢視,發現mysql cpu到了100%。開始懷疑是mysql效能的問題,不會10萬條資料就卡成這樣吧?雖然我的linux是在伺服器上放了個虛擬機器,但也不至於10萬條記錄掛啊? 網上找了一大把文章,my.cnf也設定了,我虛擬機器記憶體是2G,將key_buf設定成512M 還是卡。非常鬱悶!
最後沒辦法,只能用explain來找原因了。結果還真找到了。所以說用mysql寫查詢語句,一定要注意索引,一個不小心,效能那是十萬八千里。OK,下面分享下查詢過程:
首先上原始的查詢語句,我只用了一個id欄位,方便檢查。
explain select id from collect where vtype=1 order by id asc;
+----+-------------+---------+------+---------------+-------+---------+-------+-------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+-------+---------+-------+-------+-----------------------------+
| 1 | SIMPLE | collect | ref | vtype | vtype | 5 | const | 93237 | Using where; Using filesort |
+----+-------------+---------+------+---------------+-------+---------+-------+-------+-----------------------------+
看上面,最後的Extra 部分:竟然出現 Using filesort ! 我暈,全表查詢。但是 prossible keys 已經使用到了vtype啊? 看來並不是where 條件的問題。
為了測試,將2條語句分別執行下看:
mysql> select id from collect where vtype=1 order by id asc limit 0,20;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
| 20 |
+----+
20 rows in set (10.28 sec)
查詢20條資料,花了 10.28 秒! 非常的暈。
再看:
mysql> select id from collect where vtype=1 limit 0,20;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
| 20 |
+----+
20 rows in set (0.01 sec)
少了order by 基本上秒查!
為什麼會出現以上問題呢?order by id asc, id 欄位可是主鍵啊,按理說應該是非常快的索引,但是mysql 好像並沒有用到。再測試
mysql> explain select * from collect order by id asc;
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
| 1 | SIMPLE | collect | ALL | NULL | NULL | NULL | NULL | 103997 | Using filesort |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
看上面的分析,我直接select * order by id asc ,也是用到了filesort ,用到了這個肯定查詢在10秒以上了。
mysql> explain select id from collect order by id asc;
+----+-------------+---------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+---------+---------+------+--------+-------------+
| 1 | SIMPLE | collect | index | NULL | PRIMARY | 4 | NULL | 103997 | Using index |
+----+-------------+---------+-------+---------------+---------+---------+------+--------+-------------+
而上面的,將* 改成id ,Using index 了,看來直接查詢id 會使效能提高。
mysql> explain select id,url,title from collect order by id asc;
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
| 1 | SIMPLE | collect | ALL | NULL | NULL | NULL | NULL | 103997 | Using filesort |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------------+
1 row in set (0.00 sec)
而再加上另外的欄位,order by 就沒任何效能提高了。還是Using fielsort !
從上面可以看出order by 不能亂用!不知道網上哪個傻逼說用了limit 最好用order by 這樣會讓分頁的效能加快!簡直是放屁。經過實際測試,limit 和order by 沒有任何關聯!而以前寫程式的時候經常會用order by id asc 。 可能是資料從來沒有上過10萬條的緣故,感覺還行,今天用了10萬條採集資料做測試,慢得一塌糊塗!
好了,現在仔細想想order by 用到索引的場合:
1) 如果select 只查詢索引欄位,order by 索引欄位會用到索引,要不然就是全表排列;
2) 如果有where 條件,比如where vtype=1 order by vtype asc . 這樣order by 也會用到索引!
3) 綜上,如果order by 真的影響limit的話,那麼就請在沒有where 查詢的時候order by id(主鍵), 有where 查詢的時候,order by (索引) 欄位。
4) 別迷信網上文章,多explain,並且要相信mysql 依然很堅挺,別出現慢的情況就想,免費的效能就這樣?
測試繼續,到了100條記錄,1000萬條再來測試mysql 的效能。
測試環境:目前資料量1.4G,10萬記錄,core 4200,4G記憶體,vm6.0虛擬機器(Linux centos5 , 2G記憶體,60G硬碟)下測試!