对MySQL索引知识的总结笔记。

普通索引

索引是一种数据结构,主要用于性能的提高。

比如我们有一个表t_users,有4个字段:

1
2
3
4
5
6
7
create table t_users (
id bigint(20) not null auto_increment,
name varchar(255) not null,
age bigint(20) not null,
num bigint(20) not null,
primary key (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

往这个表中插入100w条数据,name字段是format-1到100w,age字段也是1-100w,num字段是个随机的10以内的数字。然后执行sql语句进行查询:

1
2
3
4
5
6
7
mysql> select * from t_users where name = 'format-500000';
+--------+---------------+--------+-----+
| id | name | age | num |
+--------+---------------+--------+-----+
| 500000 | format-500000 | 500000 | 38 |
+--------+---------------+--------+-----+
1 row in set (0.47 sec)

explain一下这条语句:

1
2
3
4
5
6
mysql> explain select * from t_users where name = 'format-500000';
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t_users | ALL | NULL | NULL | NULL | NULL | 996677 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

发现查询了996677条数据,进行了全表的扫描。

我们给name字段加上索引:

1
mysql> create index IDX_FOR_NAME on t_users(name);

再次执行sql语句:

1
2
3
4
5
6
7
mysql> select * from t_users where name = 'format-500000';
+--------+---------------+--------+-----+
| id | name | age | num |
+--------+---------------+--------+-----+
| 500000 | format-500000 | 500000 | 38 |
+--------+---------------+--------+-----+
1 row in set (0.00 sec)

explain一下:

1
2
3
4
5
6
7
mysql> explain select * from t_users where name = 'format-500000';
+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+
| 1 | SIMPLE | t_users | ref | IDX_FOR_NAME | IDX_FOR_NAME | 767 | const | 1 | Using index condition |
+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+
1 row in set (0.00 sec)

只查询了1条数据,因为我们加了btree索引,可以快速定位到具体的值。

接下来我们查询num字段:

1
2
3
4
5
6
7
8
9
10
mysql> select * from t_users where num = 66;
+--------+---------------+--------+-----+
....
| 965109 | format-965109 | 965109 | 66 |
| 965172 | format-965172 | 965172 | 66 |
| 965182 | format-965182 | 965182 | 66 |
| 965213 | format-965213 | 965213 | 66 |
....
+--------+---------------+--------+-----+
10029 rows in set (0.30 sec)

由于num字段也是没有加索引的,查询的时候也进行全表的扫描,查询耗时。接下来我们给num字段加上索引。

1
mysql> create index IDX_FOR_NUM on t_users(num);

然后进行查询:

1
2
3
4
5
6
7
8
9
10
mysql> select * from t_users where num = 5;
+--------+---------------+--------+-----+
....
| 965109 | format-965109 | 965109 | 5 |
| 965172 | format-965172 | 965172 | 5 |
| 965182 | format-965182 | 965182 | 5 |
| 965213 | format-965213 | 965213 | 5 |
....
+--------+---------------+--------+-----+
10029 rows in set (0.04 sec)

explain一下:

1
2
3
4
5
6
mysql> explain select * from t_users where num = 5;
+----+-------------+---------+------+---------------+-------------+---------+-------+-------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+-------------+---------+-------+-------+-------+
| 1 | SIMPLE | t_users | ref | IDX_FOR_NUM | IDX_FOR_NUM | 8 | const | 206712 | NULL |
+----+-------------+---------+------+---------------+-------------+---------+-------+-------+-------+

虽然我们在num字段上加了索引,但是由于num值在这100w条数据中有很多重复的数据,这个时候索引对查询速度的提高就没有那么明显了。

因为不论是hash类型的索引还是btree类型的索引,他们对于重复的数据的查询并没有提高多少。相反,由于添加了索引,导致数据写入性能变差,而查询性能又没有增强多少。所以说不能盲目地添加索引。

复合索引

复合索引也叫联合索引,表示索引建立在多个列上。

我们删除t_users上的索引,然后创建一个复合索引。

1
2
3
4
mysql> drop index IDX_FOR_NUM on t_users;
mysql> drop index IDX_FOR_NAME on t_users;
mysql> create index INDEX_FOR_NAME_AGE on t_users(name, age);

复合索引支持最左原则,也就是说INDEX_FOR_NAME_AGE索引支持name字段的查找,支持name,age字段的查找,但是不支持age,name字段的查找以及age字段的查找。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
mysql> explain select * from t_users where name = 'format-100000';
+----+-------------+---------+------+--------------------+--------------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+--------------------+--------------------+---------+-------+------+-----------------------+
| 1 | SIMPLE | t_users | ref | INDEX_FOR_NAME_AGE | INDEX_FOR_NAME_AGE | 767 | const | 1 | Using index condition |
+----+-------------+---------+------+--------------------+--------------------+---------+-------+------+-----------------------+
mysql> explain select * from t_users where name = 'format-100000' and age = 100000;
+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+
| 1 | SIMPLE | t_users | ref | INDEX_FOR_NAME_AGE | INDEX_FOR_NAME_AGE | 775 | const,const | 1 | Using index condition |
+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+
mysql> explain select * from t_users where age = 100000;
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t_users | ALL | NULL | NULL | NULL | NULL | 996677 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

使用age,name字段查找:

1
2
3
4
5
6
mysql> explain select * from t_users where age = 100000 and name = 'format-100000';
+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+
| 1 | SIMPLE | t_users | ref | INDEX_FOR_NAME_AGE | INDEX_FOR_NAME_AGE | 775 | const,const | 1 | Using index condition |
+----+-------------+---------+------+--------------------+--------------------+---------+-------------+------+-----------------------+

我们发现使用age,name字段的查找使用了复合索引,这是因为MySQL内部有个查询优化器帮我们进行了优化。

索引的生效

索引创建之后,查询的过程并不一定会使用索引。整理如下(t_users表中name和num字段都有单独的索引):

1.当使用索引查询比全表扫描更慢。比如下面这句sql中num字段的值分布在1-10之间

1
2
3
4
5
6
mysql> explain select * from t_users where num > 1 and num < 8;
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t_users | ALL | IDX_ON_NUM | NULL | NULL | NULL | 996504 | Using where |
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+

2.使用or进行查询,并且or左右两边的列有不存在索引的列

1
2
3
4
5
6
mysql> explain select * from t_users where name = 'format-4000' or age = 50;
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t_users | ALL | IDX_FOR_NAME | NULL | NULL | NULL | 996677 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

or两边的列都有索引:

1
2
3
4
5
6
mysql> explain select * from t_users where name = 'format-4000' or num = 50;
+----+-------------+----------+-------------+---------------------------------+---------------------------------+---------+------+------+-----------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------------+---------------------------------+---------------------------------+---------+------+------+-----------------------------------------------------------+
| 1 | SIMPLE | t_users | index_merge | IDX_ON_NUM,IDX_FOR_NAME | IDX_FOR_NAME,IDX_ON_NUM | 767,8 | NULL | 2 | Using union(IDX_FOR_NAME,IDX_ON_NUM); Using where |
+----+-------------+----------+-------------+---------------------------------+---------------------------------+---------+------+------+-----------------------------------------------------------+

3.使用like,并以 % 开头

1
2
3
4
5
6
7
8
9
10
11
12
13
mysql> explain select * from t_users where name like "%format-200";
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t_users | ALL | NULL | NULL | NULL | NULL | 996677 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
mysql> explain select * from t_users where name like "%format-200%";
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t_users | ALL | NULL | NULL | NULL | NULL | 996677 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

以 % 结尾的查询会使用索引:

1
2
3
4
5
6
mysql> explain select * from t_users where name like "format-200%";
+----+-------------+---------+-------+---------------+--------------+---------+------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+--------------+---------+------+------+-----------------------+
| 1 | SIMPLE | t_users | range | IDX_FOR_NAME | IDX_FOR_NAME | 767 | NULL | 1110 | Using index condition |
+----+-------------+---------+-------+---------------+--------------+---------+------+------+-----------------------+

4.复合索引

不是复合索引的最左字段(t_users表有(name,age)复合索引)。

1
2
3
4
5
6
mysql> explain select * from t_users where age = 100000;
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t_users | ALL | NULL | NULL | NULL | NULL | 996677 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+

5.对varchar类型的字段进行查询的时候,没有加上引号

1
2
3
4
5
6
7
8
9
10
11
12
13
mysql> explain select * from t_users where name = 111;
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | t_users | ALL | IDX_FOR_NAME | NULL | NULL | NULL | 996677 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
mysql> explain select * from t_users where name = "111";
+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+
| 1 | SIMPLE | t_users | ref | IDX_FOR_NAME | IDX_FOR_NAME | 767 | const | 1 | Using index condition |
+----+-------------+---------+------+---------------+--------------+---------+-------+------+-----------------------+

hash索引和btree索引的区别

  1. hash索引不能使用范围查询,只能使用一些比如 “=”, “<>”, “in”查询。因为hash索引会计算索引列的hash值,计算出后的hash值经过了hash算法与原先的值完全不一样,只能进行等值的过滤,不能基于范围的过滤
  2. hash索引遇到大量hash值相同的情况下,性能比btree要差
  3. hash索引并不一定一次可以定位到数据。因为基于索引列计算出的hash值会有重复,重复的话需要扫描hash表进行比较
  4. 由于hash索引中存放的是经过hash计算之后的hash值,而且hash值的大小关系并不一定和hash运算前的键值完全一样,所以数据库无法利用索引的数据来避免任何排序运算
  5. 对于组合索引,hash索引在计算hash值的时候是组合索引键合并后再一起计算hash值,而不是单独计算hash值,所以通过组合索引的前面一个或几个索引键进行查询的时候,hash索引也无法被利用
  6. InnoDB和MyISAM引擎不支持hash索引
本文作者:Format
原文链接: http://fangjian0423.github.io/2017/07/05/mysql-index-summary/

MySQL索引知识总结相关推荐

  1. Mysql索引知识概括

    Mysql索引知识概括 索引由来 索引简介 索引分类 索引分析 索引延伸 执行计划与资源消耗 索引由来 性能下降SQL慢 .执行时间长 .等待时间长: 查询语句写的烂 索引失效 关联查询太多join( ...

  2. 关于MySQL索引知识与小妙招 — 学到了!

    一.索引基本知识 1.1 索引的优点 大大减少了服务器需要扫描的数据量,加快数据库的检索速度 帮助服务器避免排序和临时表 将随机io变成顺序io 1.2 索引的用处 速查找匹配WHERE子句的行 从c ...

  3. mysql navicat 组合索引_Navicat设置MySQL索引+MySQL索引知识

    引用: https://www.cnblogs.com/bypp/p/7755307.html https://blog.csdn.net/resilient/article/details/8282 ...

  4. mysql 主表某一列 小于某一个表的两列之和_关于MySQL索引知识与小妙招

    1.1 索引的优点 大大减少了服务器需要扫描的数据量,加快数据库的检索速度 帮助服务器避免排序和临时表 将随机io变成顺序io 1.2 索引的用处 速查找匹配WHERE子句的行 从considerat ...

  5. MySQL索引知识复习

    在你享受工作舒适的同时,你的危机也已经在慢慢靠近 正确的创建合适的索引才是保证数据库性能保证的基础 1.索引的底层数据结构:hash,b树,b+树的区别,逐层分析为什么最后选用了b+树作为索引结构? ...

  6. ❤『知识集锦』一文搞懂mysql索引!!(建议收藏)

    作者:不吃西红柿 简介:CSDN博客专家.蓝桥签约作者.大数据领域优质创作者. 以我的资历和文凭,将来这个城市的大街,都归我扫.   [系列课程介绍] 『面试知识集锦』系列课程包括以下20个系列,超过 ...

  7. MySQL索引原理、失效情况

    声明:本文是小编在学习过程中,东拼西凑整理,如有雷同,纯属借鉴. Mysql5.7的版本, InnoDB引擎 目录 1 mysql索引知识 1.1 B+Tree索引 1.2 主键索引和普通索引的区别 ...

  8. 十几年老Java咳血推荐:MySQL索引原理、失效情况,两万字肝爆,建议收藏!

    一.前言 MySQL 作为主流的数据库,是各大厂面试官百问不厌的知识点,但是需要了解到什么程度呢?仅仅停留在 建库.创表.增删查改等基本操作的水平可不够.在面试后端开发的时候,一连几个问题,简直会被问 ...

  9. Mysql高级调优篇——第一章:调优必备索引知识

    1.Sql预热 常见的七种Join理论,看图就非常清晰 左连接:A独有+在A中的B部分 select * from A left join B on A.key = B.key 因为没有满足A的B,所 ...

最新文章

  1. ipykernel_launcher.py: error: unrecognized arguments: -f /Users/apple/Library/Jupyter/runtime/kernel
  2. 只需一行代码,你的纯文本秒变 Markdown
  3. 在不使用notifyDataSetChanged()方法,怎样选中Item中的内容
  4. 表示python代码块的是_编写高质量Python代码的59个有效方法,你用过几个
  5. 牛客多校3 - Operation Love(几何+叉积确定三点顺逆)
  6. C++学习笔记(三)
  7. 1682: [Usaco2005 Mar]Out of Hay 干草危机
  8. 数据链路层中的LLC
  9. 2D纹理与3D模型共存时的渲染问题
  10. tcp/ip协议详解
  11. matlab 死区,MATLAB对AC/DC/AC电源的死区效应谐波仿真
  12. 模拟手机定位软件有哪些,推荐几款
  13. 微信公众号跳转到手机默认浏览器打开指定页面功能怎样实现?
  14. 动态规划-泰波那契序列
  15. 标准C++为什么没有垃圾回收(Garbage Collection)
  16. arduino超声波测距接线图详细_Arduino系列之超声波测距模块代码(一)
  17. 7种方法实现数组去重
  18. [论文学习]Private traits and attributes are predictable from digital records of human behavior
  19. Linux学习-67-日志服务器设置和日志分析工具(logwatch)安装及使用
  20. 软著变更申请流程是什么 软著变更需要准备哪些材料?

热门文章

  1. 机器学习算法加强——数据清洗
  2. 【模型迭代】拒绝推断(RI)
  3. 腾讯正式进军电商:小鹅拼拼,出自微信
  4. Logistic Classification
  5. TalkingData大规模机器学习的应用
  6. Apache ZooKeeper - 构建ZooKeeper源码环境及StandAlone模式下的服务端和客户端启动
  7. Tomcat - 你该知道的Tomcat生产环境部署
  8. 并发编程-15并发容器(J.U.C)核心 AbstractQueuedSynchronizer 抽象队列同步器AQS介绍
  9. Centos6.5安装/运行/启动/登录docker
  10. Redis提供的持久化机制(RDB和AOF)