Mysql索引

Posted 翔之天空

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql索引相关的知识,希望对你有一定的参考价值。

 

参考:《MySQL高性能》 第五章

          《MySQL技术内幕:innodb存储引擎》 第五章

 

 

B+tree树 索引

 

聚簇索引(一级索引):主键(无主键时指定一个唯一非空索引代替,无唯一非空索引时 隐式的指定主键rowid代替),叶子节点中存储行的所有数据

辅助索引(二级索引):普通索引,叶子节点只存储索引列对应的数据主键列(用于去聚簇索引查找数据)

 

 

一、索引是顺序组织存储的,可避免排序,  将随机I/O变为顺序I/O

 

 

 

二、组合索引的排序

 

 

 

三:测试如下:

--辅助索引 组合索引的使用规则,

--1、建立测试数据
mysql> create table test_idx_comb_table(id int ,name varchar(10),score int ,class int);
Query OK, 0 rows affected (0.86 sec)

mysql> alter table test_idx_comb_table add index idx_test_idx_comb_table(id,name,score);
Query OK, 0 rows affected (0.13 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> insert into test_idx_comb_table values(1,'zhao',98,11),(2,'qian',99,11),(3,'sun',78,11),(4,'li',80,11);
Query OK, 4 rows affected (0.12 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

--2、查看测试数据
mysql> select * from test_idx_comb_table;
+------+------+-------+-------+
| id   | name | score | class |
+------+------+-------+-------+
|    1 | zhao |    98 |    11 |
|    2 | qian |    99 |    11 |
|    3 | sun  |    78 |    11 |
|    4 | li   |    80 |    11 |
+------+------+-------+-------+
4 rows in set (0.00 sec)


--3、查看执行计划
--3.1、全值匹配
mysql> explain select id,name,score,class from test_idx_comb_table  where id=3 and name='sun' and score='78';
+----+-------------+---------------------+------------+------+-------------------------+-------------------------+---------+-------------------+------+----------+-------+
| id | select_type | table               | partitions | type | possible_keys           | key                     | key_len | ref               | rows | filtered | Extra |
+----+-------------+---------------------+------------+------+-------------------------+-------------------------+---------+-------------------+------+----------+-------+
|  1 | SIMPLE      | test_idx_comb_table | NULL       | ref  | idx_test_idx_comb_table | idx_test_idx_comb_table | 43      | const,const,const |    1 |   100.00 | NULL  |
+----+-------------+---------------------+------------+------+-------------------------+-------------------------+---------+-------------------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

--3.2、索引覆盖查询
--Using index   索引覆盖扫描,server层完成,无需回表
mysql> explain select id,name,score from test_idx_comb_table  where id=3 and name='sun' and score='78';      
+----+-------------+---------------------+------------+------+-------------------------+-------------------------+---------+-------------------+------+----------+-------------+
| id | select_type | table               | partitions | type | possible_keys           | key                     | key_len | ref               | rows | filtered | Extra       |
+----+-------------+---------------------+------------+------+-------------------------+-------------------------+---------+-------------------+------+----------+-------------+
|  1 | SIMPLE      | test_idx_comb_table | NULL       | ref  | idx_test_idx_comb_table | idx_test_idx_comb_table | 43      | const,const,const |    1 |   100.00 | Using index |
+----+-------------+---------------------+------------+------+-------------------------+-------------------------+---------+-------------------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

--3.3、匹配索引最左前缀
mysql> explain select id,name,score,class from test_idx_comb_table  where id=3 ;
+----+-------------+---------------------+------------+------+-------------------------+-------------------------+---------+-------+------+----------+-------+
| id | select_type | table               | partitions | type | possible_keys           | key                     | key_len | ref   | rows | filtered | Extra |
+----+-------------+---------------------+------------+------+-------------------------+-------------------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | test_idx_comb_table | NULL       | ref  | idx_test_idx_comb_table | idx_test_idx_comb_table | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+---------------------+------------+------+-------------------------+-------------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

--3.4、匹配索引范围值
mysql> explain select id,name,score,class from test_idx_comb_table  where id between 2 and 3 ;
+----+-------------+---------------------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
| id | select_type | table               | partitions | type  | possible_keys           | key                     | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------------------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | test_idx_comb_table | NULL       | range | idx_test_idx_comb_table | idx_test_idx_comb_table | 5       | NULL |    2 |   100.00 | Using index condition |
+----+-------------+---------------------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)

--3.5、匹配索引一列并范围匹配另一列
--Using index condition (Index Condition Pushdown,ICP) 按照索引条件过滤数据行的同时 where条件中的其他条件去过滤这些数据行   
--开启时(5.6特性) 在查询id=3的数据行的同时 会根据 name like 's%'条件过滤,然后检索的结果指向聚集索引, 最后返回给用户, 减少了访问表的次数
--未开启时(5.5及之前版本) 先查询id=3的记录 ,然后检索的结果指向聚集索引,再根据name like 's%'条件过滤, 最后返回给用户
mysql> explain select id,name,score,class from test_idx_comb_table  where id=3 and name like 's%';
+----+-------------+---------------------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
| id | select_type | table               | partitions | type  | possible_keys           | key                     | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+---------------------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | test_idx_comb_table | NULL       | range | idx_test_idx_comb_table | idx_test_idx_comb_table | 38      | NULL |    1 |   100.00 | Using index condition |
+----+-------------+---------------------+------------+-------+-------------------------+-------------------------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)


--3.6、MRR特性,开启MRR优化特性(mrr_cost_based默认为on 是成本算法自行判断是否采用MRR优化,  这里设置为off 后 强制采用MRR优化)
--read_rnd_buffer
mysql> set optimizer_switch='mrr=on,mrr_cost_based=off';
Query OK, 0 rows affected (0.00 sec)

--MRR特性:通过辅助索引找到的主键 缓存起来 然后根据 主键排序后 找到记录, 这样就可以把 辅助索引找主键的随机I/O 变为根据主键排序的 顺序I/O了
--在read_rnd_buffer 中缓存起来
mysql> explain select id,name,score,class from test_idx_comb_table  where id=3 and name like 's%';
+----+-------------+---------------------+-------+-------------------------+-------------------------+---------+------+------+----------------------------------+
| id | select_type | table               | type  | possible_keys           | key                     | key_len | ref  | rows | Extra                            |
+----+-------------+---------------------+-------+-------------------------+-------------------------+---------+------+------+----------------------------------+
|  1 | SIMPLE      | test_idx_comb_table | range | idx_test_idx_comb_table | idx_test_idx_comb_table | 38      | NULL |    1 | Using index condition; Using MRR |
+----+-------------+---------------------+-------+-------------------------+-------------------------+---------+------+------+----------------------------------+
1 row in set (0.00 sec)



--3.7、无法使用索引查询不是最左前缀的列,如name,score字段匹配
--Using where   从数据表返回数据,再过滤掉不需要的数据
mysql> explain select id,name,score,class from test_idx_comb_table  where  name='sun' ;
+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table               | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | test_idx_comb_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where |
+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select id,name,score,class from test_idx_comb_table  where  score='78';                       
+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table               | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | test_idx_comb_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    4 |    25.00 | Using where |
+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

 

 

 

--4、查看索引状态:

测试已test_stat表为例,测试如下:

--1、查看表数据
mysql> select * from test_stat;
+---+---+------+------+------+------+
| a | b | c    | d    | e    | f    |
+---+---+------+------+------+------+
| 1 | 1 |   10 |   11 |  100 |  101 |
| 1 | 2 |   10 |   11 |  200 |  102 |
| 1 | 3 |   10 |   11 |  100 |  103 |
| 1 | 4 |   10 |   12 |  200 |  104 |
| 1 | 5 |   10 |   12 |  100 |  105 |
+---+---+------+------+------+------+
5 rows in set (0.07 sec)


--2、查看表信息
mysql> show create table  test_stat\\G          
*************************** 1. row ***************************
       Table: test_stat
Create Table: CREATE TABLE `test_stat` (
  `a` int(11) NOT NULL,
  `b` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  `e` int(11) DEFAULT NULL,
  `f` int(11) DEFAULT NULL,
  PRIMARY KEY (`a`,`b`),
  UNIQUE KEY `i2uniq` (`e`,`f`),
  KEY `i1` (`c`,`d`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)


--3、查看索引信息
mysql> show index from test_stat\\G
*************************** 1. row ***************************
        Table: test_stat          --表名
   Non_unique: 0                  --非唯一索引是1,唯一索引是0
     Key_name: PRIMARY            --索引名称
Seq_in_index: 1                   --索引中的位置
  Column_name: a                  --索引列的名称
    Collation: A                  --存储方式,B+ 树是A
  Cardinality: 1                  --唯一值的估算,越接近1 重复值越多,如果不准 ANALYZE TABLE 可以收集表统计信息 但最好业务低估收集
     Sub_part: NULL               --是否列的部分为索引,整列为索引时  显示null, 部分为索引时显示 具体数值 比如 key idx_a (a(2)) 就是只对前两个字段进行索引操作
       Packed: NULL               --如何被压缩,没有压缩为null
         Null:                    --索引列是否允许为null,可以为空表示为YES
   Index_type: BTREE              --索引类型,B+ 树是BTREE
      Comment:                    --注释
Index_comment:              
*************************** 2. row ***************************
        Table: test_stat
   Non_unique: 0
     Key_name: PRIMARY
Seq_in_index: 2
  Column_name: b
    Collation: A
  Cardinality: 5
     Sub_part: NULL
       Packed: NULL
         Null:
   Index_type: BTREE
      Comment:
Index_comment:
*************************** 3. row ***************************
        Table: test_stat
   Non_unique: 0
     Key_name: i2uniq
Seq_in_index: 1
  Column_name: e
    Collation: A
  Cardinality: 2
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
*************************** 4. row ***************************
        Table: test_stat
   Non_unique: 0
     Key_name: i2uniq
Seq_in_index: 2
  Column_name: f
    Collation: A
  Cardinality: 5
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
*************************** 5. row ***************************
        Table: test_stat
   Non_unique: 1
     Key_name: i1
Seq_in_index: 1
  Column_name: c
    Collation: A
  Cardinality: 1
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
*************************** 6. row ***************************
        Table: test_stat
   Non_unique: 1
     Key_name: i1
Seq_in_index: 2
  Column_name: d
    Collation: A
  Cardinality: 2
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
6 rows in set (0.00 sec)

 

 

 

--五、在线ddl

--在线ddl时,会将insert、update、delete等dml操作放到缓存中,待ddl完成后 再重做应用到表上  到达数据一致性

--缓存大小为innodb_online_alter_log_max_size,默认128M, 但缓存的dml操作空间不够时会报错  建议1G

mysql>  show variables like 'innodb_online_alter_log_max_size';
+----------------------------------+-----------+
| Variable_name                    | Value     |
+----------------------------------+-----------+
| innodb_online_alter_log_max_size | 134217728 |
+----------------------------------+-----------+
1 row in set (0.00 sec)


mysql> select 134217728/1024/1024 M;
+--------------+
| M            |
+--------------+
| 128.00000000 |
+--------------+
1 row in set (0.00 sec)

 

 

 

--六、参数优化

 

--optimizer_search_depth        //搜索深度

--默认 62, 越小越好

--如果连接7个表 可将值设置为0 、或者让优化器 自动选择表的数量的值7

 

 

 

--七、强制和忽略索引

--1、测试数据
mysql>  CREATE TABLE test_hint_index_table (
    ->   a int(11) ,
    ->   b int(11) ,
    ->   KEY (a),
    ->   KEY (b)
    -> );

mysql> insert into test_hint_index_table values(1,1),(1,2),(2,3),(2,4),(1,2);
Query OK, 5 rows affected (0.04 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)


--2、初始执行计划,走的b,a的索引
mysql>  explain select * from test_hint_index_table where a=1 and b=2\\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_hint_index_table
   partitions: NULL
         type: index_merge
possible_keys: a,b
          key: b,a
      key_len: 5,5
          ref: NULL
         rows: 1
     filtered: 100.00
        Extra: Using intersect(b,a); Using where; Using index
1 row in set, 1 warning (0.00 sec)



--3、使用use index(a)让其走a的索引,但实际没有走key为null
mysql>  explain select * from test_hint_index_table use index(a) where a=1 and b=2\\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_hint_index_table
   partitions: NULL
         type: ALL
possible_keys: a
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5
     filtered: 20.00
        Extra: Using where
1 row in set, 1 warning (0.02 sec)


--4、使用force参数强制走a索引,可以走到a的索引上
mysql> explain select * from test_hint_index_table force index(a) where a=1 and b=2\\G     
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_hint_index_table
   partitions: NULL
         type: ref
possible_keys: a
          key: a
      key_len: 5
          ref: const
         rows: 3
     filtered: 20.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)



--5、可以使用ignore参数,来忽略索引的使用
mysql>  explain select * from test_hint_index_table ignore index(a,b) where a=1 and b=2\\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test_hint_index_table
   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)

 

 

    

--八、不走索引的情况

--1、统计信息不准确,需要表分析

--设置持久化保存,统计信息的表, 查看last_update 最后更新的情况
mysql.innodb_table_stats 和 mysql.innodb_index_stats


--表分析
--对整张表
analyze table test_create_table;

--对分区表的分区
alter table t_exchange analyze partition p2;





--2、隐式转换

--建立测试表,b字段为char类型、b字段建立索引
mysql> create table test_conver_table (a int ,b varchar(10));   
mysql> create index idx_test_conver_table on test_conver_table(b);

--插入数据
DROP PROCEDURE IF EXISTS p_test_conver_table;

DELIMITER $
CREATE PROCEDURE p_test_conver_table()
BEGIN
    DECLARE i INT DEFAULT 1;
    WHILE i<=10000 DO
        INSERT INTO test_conver_table(a,b) VALUES(i,i);
        SET i = i+1;
    END WHILE;
    COMMIT;
END $innodb——

CALL p_test_conver_table();


--执行语句,b带入的是整型、不是字符型,发生隐式转换,不走索引,走的全表
mysql>  explain extended  select * from test_conver_table where b=10;
+----+-------------+-------------------+------------+------+-----------------------+------+---------+------+---------+----------+-------------+
| id | select_type | table             | partitions | type | possible_keys         | key  | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+-------------------+------------+------+-----------------------+------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | test_conver_table | NULL       | ALL  | idx_test_conver_table | NULL | NULL    | NULL | 9760364 |    10.00 | Using where |
+----+-------------+-------------------+------------+------+-----------------------+------+---------+------+---------+----------+-------------+
1 row in set, 4 warnings (0.04 sec)

--查看警告,无法匹配
mysql> show warnings;
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                           |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1681 | 'EXTENDED' is deprecated and will be removed in a future release.                                                                                                                 |
| Warning | 1739 | Cannot use ref access on index 'idx_test_conver_table' due to type or collation conversion on field 'b'                                                                           |
| Warning | 1739 | Cannot use range access on index 'idx_test_conver_table' due to type or collation conversion on field 'b'                                                                         |
| Note    | 1003 | /* select#1 */ select `flydb`.`test_conver_table`.`a` AS `a`,`flydb`.`test_conver_table`.`b` AS `b` from `flydb`.`test_conver_table` where (`flydb`.`test_conver_table`.`b` = 10) |
+---------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)



--带入b='10' 字符串类型, 或者修改表b字段为整型即可

 

 

以上是关于Mysql索引的主要内容,如果未能解决你的问题,请参考以下文章

当 MySQL 添加一个与你自己同名的函数时会发生啥?

索引法则--少用OR,它在连接时会索引失效

mysql索引

MYSQL之索引配置方法分类

当我用尽 bigint 生成的密钥时会发生啥?如何处理?

当我用尽 bigint 生成的密钥时会发生啥?如何处理?