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)

猜你喜欢

转载自blog.csdn.net/aryoyo/article/details/80672374