mysql索引和explain執行計劃分析

mysql索引:
MyISAM引擎使用B+Tree作爲索引結構,和DB2的索引一樣,葉節點的data域存放的是數據記錄的地址,
InnoDB的引擎的cluster index葉子節點存放的就是數據本身,如果表沒有primary key或者unique  key,
那麼InnoDB默認會以隱藏字段DB_ROW_ID作爲key創建cluster index,二級索引的葉子節點則存放的是
主鍵的值.
問題:cluster index的主要目的是數據頁的物理和索引鍵的順序一致,這樣在獲取一組範圍的數據的時候
可以讀取連續數據頁減少I/O和數據頁數.InnoDB默認以DB_ROW_ID創建cluster index或者人爲創建自增
字段作爲主鍵,這樣可以連續插入數據頁,是可以避免insert或者update等寫性能影響,可是這樣的主鍵
又不是常用被搜索鍵值,所以這樣的cluster index的好處是什麼呢?使用二級索引的時候,豈不是要進行
二次索引搜索?

瞭解索引幫助分析explain輸出,參考官方文檔:
https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

EXPLAIN Join Types:幾種常見類型由好到差:
 const,system-> ref->range->index->All 

測試:create table t(a int primary key,b int,c int);
          insert into t2 values(1,11,111),(2,22,222),(5,56,565),(9,32,322),(7,23,233);
          create index bidx on t(b);

1.const:一行符合條件而且使用主鍵

mysql> explain select * from t where a=2\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)
2.ref:
ref官方解釋和例子:
All rows with matching index values are read from this table for each combination
 of rows from the previous tables. ref is used if the join uses only a leftmost prefix
 of the key or if the key is not a PRIMARY KEY or UNIQUE index (in other words, if 
the join cannot select a single row based on the key value). If the key that is used 
matches only a few rows, this is a good join type
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;

這裏測試使用非主鍵或非唯一鍵,返回匹配某個單獨值的所有行,也是ref:
mysql> explain select * from t where b=22\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: ref
possible_keys: bidx
          key: bidx
      key_len: 5
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

如果把*改成a,b,extra就變成了using index,就是覆蓋索引,即所有值都可以從索引中獲得:
mysql> explain select a,b from t where b=22\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: ref
possible_keys: bidx
          key: bidx
      key_len: 5
          ref: const
         rows: 1
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)
3.rang:使用索引讀取了一定範圍的數據
Only rows that are in a given range are retrieved, using an index to select the rows. 
The key column in the output row indicates which index is used. The key_len contains 
the longest key part that was used. The ref column is NULL for this type.
 
mysql> explain select * from t where a>3 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: range
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: NULL
         rows: 3
     filtered: 100.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

4.index:SQL語句只訪問索引列

mysql> explain select a,b from t \G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: index
possible_keys: NULL
          key: bidx
      key_len: 5
          ref: NULL
         rows: 5
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)

5.All:全表掃描

sql> explain select * from t where c=222\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5
     filtered: 20.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

6.刪除原來bidx索引,在b,c列創建聯合索引create index bcidx on t(b,c);

排序時候可以使用索引:
mysql> explain select * from t where b=11 order by c\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: ref
possible_keys: bcidx
          key: bcidx
      key_len: 5
          ref: const
         rows: 3
     filtered: 100.00
        Extra: Using where; Using index
1 row in set, 1 warning (0.00 sec)

把聯合索引b改爲範圍查找,索引b後面的字段失效,排序無法使用索引:
mysql> explain select * from t where b>11 order by c\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: range
possible_keys: bcidx
          key: bcidx
      key_len: 5
          ref: NULL
         rows: 4
     filtered: 100.00
        Extra: Using where; Using index; Using filesort
1 row in set, 1 warning (0.00 sec)

排序順序和索引順序不一樣,排序也無法使用索引:
mysql> explain select * from t order by b desc,c\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
   partitions: NULL
         type: index
possible_keys: NULL
          key: bcidx
      key_len: 10
          ref: NULL
         rows: 7
     filtered: 100.00
        Extra: Using index; Using filesort
1 row in set, 1 warning (0.00 sec)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章