一.語法
explain < table_name >
例如: explain select * from t3 where id=3952602;
二.explain輸出解釋
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 1.id
1. id 我的理解是SQL執行的順利的標識,SQL從大到小的執行.
例如:
MySQL> explain select * from (select * from ( select * from t3 where id=3952602) a) b; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | PRIMARY | | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | | system | NULL | NULL | NULL | NULL | 1 | |
| 3 | DERIVED | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | | 1 | |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
很顯然這條SQL是從裡向外的執行,就是從id=3 向上執行.
2. select_type就是select類型,可以有以下幾種
(1) SIMPLE
簡單SELECT(不使用UNION或子查詢等) 例如:
MySQL> explain select * from t3 where id=3952602; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | SIMPLE | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | const | 1 | |
+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+
(2). PRIMARY
我的理解是最外層的select.例如:
MySQL> explain select * from (select * from t3 where id=3952602) a ; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | PRIMARY | | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | | 1 | |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
(3).UNION
UNION中的第二個或後面的SELECT語句.例如
MySQL> explain select * from t3 where id=3952602 union all select * from t3 ; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | PRIMARY | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | const | 1 | |
| 2 | UNION | t3 | ALL | NULL | NULL | NULL | NULL | 1000 | |
|NULL | UNION RESULT | | ALL | NULL | NULL | NULL | NULL | NULL | |
+----+--------------+------------+-------+-------------------+---------+---------+-------+------+-------+
(4).DEPENDENT UNION
UNION中的第二個或後面的SELECT語句,取決於外面的查詢
MySQL> explain select * from t3 where id in (select id from t3 where id=3952602 union all select id from t3) ; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | PRIMARY | t3 | ALL | NULL | NULL | NULL | NULL | 1000 | Using where |
| 2 | DEPENDENT SUBQUERY | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | const | 1 | Using index |
| 3 | DEPENDENT UNION | t3 | eq_ref | PRIMARY,idx_t3_id | PRIMARY | 4 | func | 1 | Using where; Using index |
|NULL | UNION RESULT | | ALL | NULL | NULL | NULL | NULL | NULL | |
+----+--------------------+------------+--------+-------------------+---------+---------+-------+------+--------------------------+
(5).UNION RESULT
UNION的結果。
MySQL> explain select * from t3 where id=3952602 union all select * from t3 ; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | PRIMARY | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | const | 1 | |
| 2 | UNION | t3 | ALL | NULL | NULL | NULL | NULL | 1000 | |
|NULL | UNION RESULT | | ALL | NULL | NULL | NULL | NULL | NULL | |
+----+--------------+------------+-------+-------------------+---------+---------+-------+------+-------+
(6).SUBQUERY
子查詢中的第一個SELECT.
MySQL> explain select * from t3 where id = (select id from t3 where id=3952602 ) ; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | PRIMARY | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | const | 1 | |
| 2 | SUBQUERY | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | | 1 | Using index |
+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------------+
(7). DEPENDENT SUBQUERY
子查詢中的第一個SELECT,取決於外面的查詢
MySQL> explain select id from t3 where id in (select id from t3 where id=3952602 ) ; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | PRIMARY | t3 | index | NULL | PRIMARY | 4 | NULL | 1000 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | const | 1 | Using index |
+----+--------------------+-------+-------+-------------------+---------+---------+-------+------+--------------------------+
(8).DERIVED
派生表的SELECT(FROM子句的子查詢)
MySQL> explain select * from (select * from t3 where id=3952602) a ; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | PRIMARY | | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | | 1 | |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
3.table
顯示這一行的數據是關於哪張表的.
有時不是真實的表名字,看到的是derivedx(x是個數字,我的理解是第幾步執行的結果)
MySQL> explain select * from (select * from ( select * from t3 where id=3952602) a) b; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | PRIMARY | | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | | system | NULL | NULL | NULL | NULL | 1 | |
| 3 | DERIVED | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | | 1 | |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
4.type
這列很重要,顯示了連接使用了哪種類別,有無使用索引.
從最好到最差的連接類型為const、eq_reg、ref、range、indexhe和ALL
(1).system
這是const聯接類型的一個特例。表僅有一行滿足條件.如下(t3表上的id是 primary key)
MySQL> explain select * from (select * from t3 where id=3952602) a ; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | PRIMARY | | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | | 1 | |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
(2).const
表最多有一個匹配行,它將在查詢開始時被讀取。因為僅有一行,在這行的列值可被優化器剩余部分認為是常數。const表很快,因為它們只讀取一次!
const用於用常數值比較PRIMARY KEY或UNIQUE索引的所有部分時。在下面的查詢中,tbl_name可以用於const表:
SELECT * from tbl_name WHERE primary_key=1;
SELECT * from tbl_name WHERE primary_key_part1=1和 primary_key_part2=2;
例如:
MySQL> explain select * from t3 where id=3952602; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | SIMPLE | t3 | const | PRIMARY,idx_t3_id | PRIMARY | 4 | const | 1 | |
+----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+
(3). eq_ref
對於每個來自於前面的表的行組合,從該表中讀取一行。這可能是最好的聯接類型,除了const類型。它用在一個索引的所有部分被聯接使用並且索引是UNIQUE或PRIMARY KEY。
eq_ref可以用於使用= 操作符比較的帶索引的列。比較值可以為常量或一個使用在該表前面所讀取的表的列的表達式。
在下面的例子中,MySQL可以使用eq_ref聯接來處理ref_tables:
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;
例如
MySQL> create unique index idx_t3_id on t3(id) ;
Query OK, 1000 rows affected (0.03 sec)
Records: 1000 Duplicates: 0 Warnings: 0
MySQL> explain select * from t3,t4 where t3.id=t4.accountid; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | SIMPLE | t4 | ALL | NULL | NULL | NULL | NULL | 1000 | |
| 1 | SIMPLE | t3 | eq_ref | PRIMARY,idx_t3_id | idx_t3_id | 4 | dbatest.t4.accountid | 1 | |
+----+-------------+-------+--------+-------------------+-----------+---------+----------------------+------+-------+
(4).ref
對於每個來自於前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。如果聯接只使用鍵的最左邊的前綴,或如果鍵不是UNIQUE或 PRIMARY KEY(換句話說,如果聯接不能基於關鍵字選擇單個行的話),則使用ref。如果使用的鍵僅僅匹配少量行,該聯接類型是不錯的。
ref可以用於使用=或<=>操作符的帶索引的列。
在下面的例子中,MySQL可以使用ref聯接來處理ref_tables:
SELECT * FROM ref_table WHERE key_column=expr;
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;
例如:
MySQL> drop index idx_t3_id on t3;
Query OK, 1000 rows affected (0.03 sec)
Records: 1000 Duplicates: 0 Warnings: 0
MySQL> create index idx_t3_id on t3(id) ;
Query OK, 1000 rows affected (0.04 sec)
Records: 1000 Duplicates: 0 Warnings: 0
MySQL> explain select * from t3,t4 where t3.id=t4.accountid; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | SIMPLE | t4 | ALL | NULL | NULL | NULL | NULL | 1000 | |
| 1 | SIMPLE | t3 | ref | PRIMARY,idx_t3_id | idx_t3_id | 4 | dbatest.t4.accountid | 1 | | 2 rows in set (0.00 sec)
(5). ref_or_null
該聯接類型如同ref,但是添加了MySQL可以專門搜索包含NULL值的行。在解決子查詢中經常使用該聯接類型的優化。
在下面的例子中,MySQL可以使用ref_or_null聯接來處理ref_tables:
SELECT * FROM ref_table
WHERE key_column=expr OR key_column IS NULL;
(6). index_merge
該聯接類型表示使用了索引合並優化方法。在這種情況下,key列包含了使用的索引的清單,key_len包含了使用的索引的最長的關鍵元素。
例如:
MySQL> explain select * from t4 where id=3952602 or accountid=31754306 ; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | SIMPLE | t4 | index_merge | idx_t4_id, idx_t4_accountid | idx_t4_id,idx_t4_accountid | 4,4 | NULL | 2 | Using union(idx_t4_id,idx_t4_accountid); Using where | 1 row in set (0.00 sec)
(7). unique_subquery
該類型替換了下面形式的IN子查詢的ref:
value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery是一個索引查找函數,可以完全替換子查詢,效率更高。
(8).index_subquery
該聯接類型類似於unique_subquery。可以替換IN子查詢,但只適合下列形式的子查詢中的非唯一索引:
value IN (SELECT key_column FROM single_table WHERE some_expr)
(9).range
只檢索給定范圍的行,使用一個索引來選擇行。key列顯示使用了哪個索引。key_len包含所使用索引的最長關鍵元素。在該類型中ref列為NULL。
當使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比較關鍵字列時,可以使用range
MySQL> explain select * from t3 where id=3952602 or id=3952603 ; | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | | 1 | SIMPLE | t3 | range | PRIMARY,idx_t3_id | idx_t3_id | 4 | NULL | 2 | Using where | 1 row in set (0.02 sec)
(10).index
該聯接類型與ALL相同,除了只有索引樹被掃描。這通常比ALL快,因為索引文件通常比數據文件小。
當查詢只使用作為單索引一部分的列時,MySQL可以使用該聯接類型。
(11). ALL
對於每個來自於先前的表的行組合,進行完整的表掃描。如果表是第一個沒標記const的表,這通常不好,並且通常在它情況下很差。通常可以增加更多的索引而不要使用ALL,使得行能基於前面的表中的常數值或列值被檢索出。
5.possible_keys
possible_keys列指出MySQL能使用哪個索引在該表中找到行。注意,該列完全獨立於EXPLAIN輸出所示的表的次序。這意味著在possible_keys中的某些鍵實際上不能按生成的表次序使用。
如果該列是NULL,則沒有相關的索引。在這種情況下,可以通過檢查WHERE子句看是否它引用某些列或適合索引的列來提高你的查詢性能。如果是這樣,創造一個適當的索引並且再次用EXPLAIN檢查查詢
6. key
key列顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL。要想強制MySQL使用或忽視possible_keys列中的索引,在查詢中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
7.key_len
key_len列顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。
使用的索引的長度。在不損失精確性的情況下,長度越短越好
8. ref
ref列顯示使用哪個列或常數與key一起從表中選擇行。
9. rows
rows列顯示MySQL認為它執行查詢時必須檢查的行數。
10. Extra
該列包含MySQL解決查詢的詳細信息,下面詳細.
(1).Distinct
一旦MySQL找到了與行相聯合匹配的行,就不再搜索了
(2).Not exists
MySQL優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標准的行,
就不再搜索了
(3).Range checked for each
Record(index map:#)
沒有找到理想的索引,因此對於從前面表中來的每一個行組合,MySQL檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連接之一
(4).Using filesort
看到這個的時候,查詢就需要優化了。MySQL需要進行額外的步驟來發現如何對返回的行排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行
(5).Using index
列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對表的全部的請求列都是同一個索引的部分的時候
(6).Using temporary
看到這個的時候,查詢需要優化了。這裡,MySQL需要創建一個臨時表來存儲結果,這通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上
(7).Using where
使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。如果不想返回表中的全部行,並且連接類型ALL或index,這就會發生,或者是查詢有問題
****************************************************************************************************************
MySQL explain的使用說明
explain顯示了MySQL如何使用索引來處理select語句以及連接表。可以幫助選擇更好的索引和寫出更優化的查詢語句。
使用方法,在select語句前加上explain就可以了:
如:explain select surname,first_name form a,b where a.id=b.id
分析結果形式如下:
EXPLAIN列的解釋:
table 顯示這一行的數據是關於哪張表的
type 這是重要的列,顯示連接使用了何種類型。從最好到最差的連接類型為const、eq_reg、ref、range、indexhe和ALL
possible_keys 顯示可能應用在這張表中的索引。如果為空,沒有可能的索引。可以為相關的域從WHERE語句中選擇一個合適的語句
key 實際使用的索引。如果為NULL,則沒有使用索引。很少的情況下,MYSQL會選擇優化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX(indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MySQL忽略索引
key_len 使用的索引的長度。在不損失精確性的情況下,長度越短越好
ref 顯示索引的哪一列被使用了,如果可能的話,是一個常數
rows MySQL認為必須檢查的用來返回請求數據的行數
Extra 關於MYSQL如何解析查詢的額外信息。將在表4.3中討論,但這裡可以看到的壞的例子是Using temporary和Using filesort,意思MySQL根本不能使用索引,結果是檢索會很慢 extra 列返回的描述的意義
Distinct 一旦MySQL找到了與行相聯合匹配的行,就不再搜索了
Not exists MySQL優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標准的行,就不再搜索了
Range checked for each
Record(index map:#)沒有找到理想的索引,因此對於從前面表中來的每一個行組合,MySQL檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連接之一
Using filesort 看到這個的時候,查詢就需要優化了。MySQL需要進行額外的步驟來發現如何對返回的行排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行
Using index 列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對表的全部的請求列都是同一個索引的部分的時候
Using temporary 看到這個的時候,查詢需要優化了。這裡,MySQL需要創建一個臨時表來存儲結果,這通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上
Where used 使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。如果不想返回表中的全部行,並且連接類型ALL或index,這就會發生,或者是查詢有問題不同連接類型的解釋(按照效率高低的順序排序)
system 表只有一行:system表。這是const連接類型的特殊情況
const 表中的一個記錄的最大值能夠匹配這個查詢(索引可以是主鍵或惟一索引)。因為只有一行,這個值實際就是常數,因為MySQL先讀這個值然後把它當做常數來對待
eq_ref 在連接中,MySQL在查詢時,從前面的表中,對每一個記錄的聯合都從表中讀取一個記錄,它在查詢使用了索引為主鍵或惟一鍵的全部時使用
ref 這個連接類型只有在查詢使用了不是惟一或主鍵的鍵或者是這些類型的部分(比如,利用最左邊前綴)時發生。對於之前的表的每一個行聯合,全部記錄都將從表中讀出。這個類型嚴重依賴於根據索引匹配的記錄多少—越少越好
range 這個連接類型使用索引返回一個范圍中的行,比如使用>或<查找東西時發生的情況
index 這個連接類型對前面的表中的每一個記錄聯合進行完全掃描(比ALL更好,因為索引一般小於表數據)
ALL 這個連接類型對於前面的每一個記錄聯合進行完全掃描,這一般比較糟糕,應該盡量避免
**********************************************************************************************************************
explain的語法如下:explain [extended] select ... from ... where ... 如果使用了extended,那麼在執行完explain語句後,可以使用show warnings語句查詢相應的優化信息。 ==============================================================mk-visual-explain工具擴展了explain,它提供了一種更直觀的樹形表現形式,使用方法很簡單:mk-visual-explain <file_containing_explain_output>
mk-visual-explain -c <file_containing_query>
mysql -e "explain select * from mysql.user" | mk-visual-explain 也可以在MySQL命令行裡通過設置pager的方式來執行:MySQL> pager mk-visual-explain
MySQL> explain [extended] select ... from ... where ... ============================================================== 進入正題,為了讓例子更具體化,我們先來建一個表,插入一點測試數據: CREATE TABLE IF NOT EXISTS `article` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`author_id` int(10) unsigned NOT NULL,
`category_id` int(10) unsigned NOT NULL,
`vIEws` int(10) unsigned NOT NULL,
`comments` int(10) unsigned NOT NULL,
`title` varbinary(255) NOT NULL,
`content` text NOT NULL,
PRIMARY KEY (`id`)
); INSERT INTO `article`
(`author_id`, `category_id`, `vIEws`, `comments`, `title`, `content`) VALUES
(1, 1, 1, 1, '1', '1'),
(2, 2, 2, 2, '2', '2'); 缺省只建了一個主鍵,沒有建其他的索引。測試時,如果你時間充裕,應該盡可能插入多一點的測試數據,怎麼說也應該保證幾千條。如果數據量過少,可能會影響 MySQL在索引選擇上的判斷。如此一來,一旦產品上線,數據量增加。索引往往不會按照你的預想工作。下面讓我們設置一個任務:查詢category_id為1且comments大於1的情況下,vIEws最多的article_id。問題很簡單,SQL也很簡單:SELECT author_id
FROM `article`
WHERE category_id = 1 AND comments > 1
ORDER BY vIEws DESC
LIMIT 1 下面讓我們用explain命令查看索引效果:EXPLAIN SELECT author_id
FROM `article`
WHERE category_id = 1
AND comments > 1
ORDER BY vIEws DESC
LIMIT 1這時explain部分結果如下:type: ALL
key: NULL
Extra: Using where; Using filesort 顯示數據庫進行了全表掃描,沒有用到索引,並且在過程中文件排序。這樣的結果肯定是糟糕的,下面讓我們通過建立索引優化一下它: ALTER TABLE `article` ADD INDEX x ( `category_id` , `comments`, `vIEws` ) ; 這時explain部分結果如下:type: range
key: x
Extra: Using where; Using filesort 雖然不再是全表掃描了,但是仍然存在文件排序。一般來說,文件排序都是由於ORDER BY語句一起的,而我們已經把views字段放到了聯合索引裡面,為什麼沒有效果呢?這是因為按照BTree的工作原理,先排序category_id,如果遇到相同的category_id則再排序comments,如果遇到相同的comments則再排序views。當comments字段在聯合索引裡處於中間位置時,因為comments > 1條件是一個范圍值(所謂range),MySQL目前無法利用索引再對後面的vIEws部分進行檢索,如果換成是是comments in ('a', 'b', 'c')這樣的多等情況則可以,關於這一點,在High Performance MySQL一書中專門有過敘述,名為Avoiding Multiple Range Conditions,在復合索引裡,僅僅只能保存一個range類型的查詢字段,並且要放到復合索引的末尾,否則,range類型查詢字段後面的索引無效。詳細的介紹大家可以自己查閱。從這個意義上來說,此時的category_id, comments, views復合索引的效果不會比category_id, comments復合索引的效果好。文件排序是否會引起性能問題要視數據分布情況而定。這裡有一個案例可供參考:多數情況下應該避免出現它。此時可以這樣設置索引:ALTER TABLE `article` ADD INDEX y ( `category_id` , `vIEws` ) ; 這時explain部分結果如下:type: range
key: x
Extra: Using where; Using filesort 很奇怪,系統無視我們剛建立的y索引,還使用x索引。導致仍然存在文件排序。如果你也出現了類似的情況,可以使用強制索引:EXPLAIN SELECT author_id
FROM `article`
FORCE INDEX ( y )
WHERE category_id = 1
AND comments > 1
ORDER BY vIEws DESC
LIMIT 1 這時explain部分結果如下:type: ref
key: y
Extra: Using where也可以刪除x索引,那樣系統會自動使用y索引(有時候MySQL比較傻,所以你得會使用FORCE INDEX)。後記:Explain的type顯示的是訪問類型,是較為重要的一個指標,結果值從好到壞依次是: system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL 一般來說,得保證查詢至少達到range級別,最好能達到ref,否則就可能會出現性能問題。 Explain的Extra信息也相當重要,如果此信息顯示Using filesort或者Using temporary的話,噩夢即將開始,不過也不盡然,比如說在一個WHERE ... ORDER BY ... 類型的查詢裡,很多時候我們無法創建一個兼顧WHERE和ORDER BY的索引,此時如果按照WHERE來確定索引,那麼在ORDER BY時,就必然會引起Using filesort,文件排序是好是壞需要仔細判斷,說白了就是看是先過濾再排序劃算,還是先排序再過濾劃算,正確答案取決與數據分布的情況,具體的情況可以參考。 Explain具體含義參見此鏈接:http://dev.MySQL.com/doc/refman/5.1/en/using-explain.Html
*************************************************************************************************************
EXPLAIN 是MySQL解釋select查詢的一個關鍵字,可以很方便的用於調試 EXPLAIN tbl_name EXPLAIN SELECT select_options
EXPLAIN 語句可以被當作 DESCRIBE 的同義詞來用,也可以用來獲取一個MySQL要執行的 SELECT 語句的相關信息。 EXPLAIN tbl_name 語法和 DESCRIBE tbl_name 或 SHOW COLUMNS FROM tbl_name 一樣。 當在一個 SELECT 語句前使用關鍵字 EXPLAIN 時,MySQL會解釋了即將如何運行該 SELECT 語句,它顯示了表如何連接、連接的順序等信息。 以下信息為引用: 在explain我們所使用的sql的時候,經常會遇到using filesort這種情況,原以為是由於有相同列值的原因引起,結果昨天看到公司的一個sql,跟同事討論了下加上自己又做了一些測試,突然發現自己原來的想法是錯誤的。 首先,只有在order by 數據列的時候才可能會出現using filesort,而且如果你不對進行order by的這一列設置索引的話,無論列值是否有相同的都會出現using filesort。因此,只要用到order by 的這一列都應該為其建立一個索引。 其次,在這次測試中,使用了一個稍微有點復雜的例子來說明這個問題,下面詳細用這個例子說一下: SELECT * FROM DB.TB WHERE ID=2222 AND FID IN (9,8,3,13,38,40) ORDER BY INVERSE_DATE LIMIT 0, 5
裡面建立的索引為一個三列的多列索引:IDX(ID,FID ,INVERSE_DATE) 。INVERSE_DATE這個是時間的反向索引。 對於這個sql我當時最開始認為應該是個優化好的狀態,應該沒有什麼纰漏了,結果一explain才發現竟然出現了:Using where; Using filesort。 為什麼呢,後來經過分析才得知,原來在多列索引在建立的時候是以B-樹結構建立的,因此建立索引的時候是先建立ID的按順序排的索引,在相同ID的情況下建立FID按 順序排的索引,最後在FID 相同的情況下建立按INVERSE_DATE順序排的索引,如果列數更多以此類推。有了這個理論依據我們可以看出在這個sql使用這個IDX索引的時候只是用在了order by之前,order by INVERSE_DATE 實際上是using filesort出來的。。汗死了。。因此如果我們要在優化一下這個sql就應該為它建立另一個索引IDX(ID,INVERSE_DATE),這樣就消除了using filesort速度也會快很多。問題終於解決了。