MySQL全面瓦解23:MySQL索引实现和使用
MySQL索引实现
InnoDB引擎中的索引
| 非聚集索引类型 | 说明 |
|---|---|
| 单列索引 | 一个索引只包含一个列 |
| 多列索引(复合索引) | 一个索引包含多个列 |
| 唯一索引 | 索引列的值必须唯一,允许有一个空值 |
MyISAM引擎中的索引
InnoDB数据检索过程
上面的表中有2个索引:id作为主键索引,name作为辅助索引。
如果需要查询id=14的数据,只需要在左边的主键索引中检索就可以了。
MyISAM数据检索过程
1、在索引中找到对应的关键字,获取关键字对应的记录的地址
2、通过记录的地址查找到对应的数据记录
索引管理和使用
数据准备
请参考第21篇(MySQL全面瓦解21(番外):一次深夜优化亿级数据分页的奇妙经历)中模拟的千万数据,我们以这个数据为测试数据。
创建索引
1 create [unique] index index_name on t_name(c_name[(length)]);
create [unique] index index_name on t_name(c_name[(length)]);
删除索引
1 drop index index_name on t_name;
查看索引
1 show index from t_name;
索引修改
示例
emp表中有500W数据 我们用emp来做测试
1 mysql> select count(*) from emp;
2 +----------+
3 | count(*) |
4 +----------+
5 | 5000000 |
6 +----------+
7 1 row in set
查看和创建索引
记得我们之前在emp表上做过索引,所以先看一下这个表目前所有的索引
可以看到,目前主键字段id和depno字段上都有建立索引
1 mysql> desc emp;
2 +----------+-----------------------+------+-----+---------+----------------+
3 | Field | Type | Null | Key | Default | Extra |
4 +----------+-----------------------+------+-----+---------+----------------+
5 | id | int(10) unsigned | NO | PRI | NULL | auto_increment |
6 | empno | mediumint(8) unsigned | NO | | 0 | |
7 | empname | varchar(20) | NO | | | |
8 | job | varchar(9) | NO | | | |
9 | mgr | mediumint(8) unsigned | NO | | 0 | |
10 | hiredate | datetime | NO | | NULL | |
11 | sal | decimal(7,2) | NO | | NULL | |
12 | comn | decimal(7,2) | NO | | NULL | |
13 | depno | mediumint(8) unsigned | NO | MUL | 0 | |
14 +----------+-----------------------+------+-----+---------+----------------+
15 9 rows in set
16
17 mysql> show index from emp;
18 +-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
19 | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
20 +-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
21 | emp | 0 | PRIMARY | 1 | id | A | 4952492 | NULL | NULL | | BTREE | | |
22 | emp | 1 | idx_emp_id | 1 | id | A | 4952492 | NULL | NULL | | BTREE | | |
23 | emp | 1 | idx_emp_depno | 1 | depno | A | 18 | NULL | NULL | | BTREE | | |
24 +-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
25 3 rows in set
我们在没有做索引的字段上做一下查询看看,在500W数据中查询一个名叫LsHfFJA的员工,消耗 2.239S

再看看他的执行过程,扫描了4952492 条数据才找到该行数据:
1 mysql> explain select * from emp where empname='LsHfFJA';
2 +----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
3 | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
4 +----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
5 | 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 4952492 | Using where |
6 +----+-------------+-------+------+---------------+------+---------+------+---------+-------------+
7 1 row in set
我们在empname这个字段上建立索引
1 mysql> create index idx_emp_empname on emp(empname);
2 Query OK, 0 rows affected
3 Records: 0 Duplicates: 0 Warnings: 0
4
5 mysql> show index from emp;
6 +-------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
7 | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
8 +-------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
9 | emp | 0 | PRIMARY | 1 | id | A | 4952492 | NULL | NULL | | BTREE | | |
10 | emp | 1 | idx_emp_id | 1 | id | A | 4952492 | NULL | NULL | | BTREE | | |
11 | emp | 1 | idx_emp_depno | 1 | depno | A | 18 | NULL | NULL | | BTREE | | |
12 | emp | 1 | idx_emp_empname | 1 | empname | A | 1650830 | NULL | NULL | | BTREE | | |
13 +-------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
14 4 rows in set
再看一下这个执行效率,就会发现有质的飞跃:0.001S,就是这么神奇,学过之前那篇的B+ Tree就知道,它不用从头开始扫表核对,而是很小次数的io读取

再看看他的执行过程,一次定位到该条数据:
1 mysql> explain select * from emp where empname='LsHfFJA';
2 +----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-----------------------+
3 | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
4 +----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-----------------------+
5 | 1 | SIMPLE | emp | ref | idx_emp_empname | idx_emp_empname | 22 | const | 1 | Using index condition |
6 +----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-----------------------+
7 1 row in set
设置合适的索引长度
根据我们之前的了解,每个磁盘块(disk)存储的内容是有限的,如果一个页中可以存储的索引记录越多,那么查询效率就会提高,所以我们可以指定索引的字段长度。
但并不是越短越好,要保证字符类型字段查询有足够高的区分度,如果只设置了一个长度,反而导致查询的相似匹配度不高。
长度的原则是要恰到好处,太长索引文件就会变大,因此要在区分度和长度上做一个平衡。
如果在我们搜索的内容中,最后的内容是一致的或者高度一致的,那我们就可以省略,比如在用户的email字段上做索引,几乎前10个字符是不一样的,结尾限定在 @****,那么通过前面10个字符就可以定位一个email地址了。
我们在该字段创建索引的时候就可以指定长度为10,这样相对于整个email字段更短些,查询效果确却基本一样,这样一个页中也可以存储更多的索引记录。
像我们上面的那个 empname 字段,基本都是6位数的,只是小部分是超过6位数,而且后缀基本一致,所以6位数之后的区分度差不多。
有一个判断 高区分度以及合适长度索引 的通用算法,如下:
1 select count(distinct left(`c_name`,calcul_len))/count(*) from t_name;
下面是对 empname 做的分析,匹配度越高搜索效率越高:
1 mysql> select count(distinct left(`empname`,3))/count(*) from emp;
2 +--------------------------------------------+
3 | count(distinct left(`empname`,3))/count(*) |
4 +--------------------------------------------+
5 | 0.0012 |
6 +--------------------------------------------+
7 1 row in set
8
9 mysql> select count(distinct left(`empname`,4))/count(*) from emp;
10 +--------------------------------------------+
11 | count(distinct left(`empname`,4))/count(*) |
12 +--------------------------------------------+
13 | 0.0076 |
14 +--------------------------------------------+
15 1 row in set
16
17 mysql> select count(distinct left(`empname`,6))/count(*) from emp;
18 +--------------------------------------------+
19 | count(distinct left(`empname`,6))/count(*) |
20 +--------------------------------------------+
21 | 0.1713 |
22 +--------------------------------------------+
23 1 row in set
24
25 mysql> select count(distinct left(`empname`,7))/count(*) from emp;
26 +--------------------------------------------+
27 | count(distinct left(`empname`,7))/count(*) |
28 +--------------------------------------------+
29 | 0.1713 |
30 +--------------------------------------------+
31 1 row in set
删除索引
1 mysql> drop index idx_emp_empname on emp;
2 Query OK, 0 rows affected
3 Records: 0 Duplicates: 0 Warnings: 0
4
5 mysql> show index from emp;
6 +-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
7 | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
8 +-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
9 | emp | 0 | PRIMARY | 1 | id | A | 4952492 | NULL | NULL | | BTREE | | |
10 | emp | 1 | idx_emp_id | 1 | id | A | 4952492 | NULL | NULL | | BTREE | | |
11 | emp | 1 | idx_emp_depno | 1 | depno | A | 18 | NULL | NULL | | BTREE | | |
12 +-------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
13 3 rows in set
执行完删除命令再查看,发现索引已经没了
小结
本文只是理解索引的基本用法,后面会认真讲一讲索引的性能分析和优化策略。
总之,理想的索引应该符合以下特征:
1、相对低频的写操作,以及高频的查询的表和字段上建立索引
2、字段区分度高
3、长度小(合适的长度,不是越小越好)
4、尽量能够覆盖常用字段
MySQL全面瓦解23:MySQL索引实现和使用的更多相关文章
- MySQL全面瓦解22:索引的介绍和原理分析
索引的定义 MySQL官方对索引的定义为:索引(Index)是协助MySQL高效获取数据的数据结构. 本质上,索引的目的是为了提高查询效率,通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时 ...
- MySQL全面瓦解24:构建高性能索引(策略篇)
学习如果构建高性能的索引之前,我们先来了解下之前的知识,以下两篇是基础原理,了解之后,对面后续索引构建的原则和优化方法会有更清晰的理解: MySQL全面瓦解22:索引的介绍和原理分析 MySQL全面瓦 ...
- MySQL全面瓦解25:构建高性能索引(案例分析篇)
回顾一下上面几篇索引相关的文章: MySQL全面瓦解22:索引的介绍和原理分析 MySQL全面瓦解23:MySQL索引实现和使用 MySQL全面瓦解24:构建高性能索引(策略篇) 索引的十大原则 1. ...
- [MySQL Reference Manual] 23 Performance Schema结构
23 MySQL Performance Schema 23 MySQL Performance Schema 23.1 性能框架快速启动 23.2 性能框架配置 23.2.1 性能框架编译时配置 2 ...
- MySQL全面瓦解13:系统函数相关
概述 提到MySQL的系统函数,我们前面有使用过聚合函数,其实只是其中一小部分.MySQL提供很多功能强大.方便易用的函数,使用这些函数,可以极大地提高用户对于数据库的管理效率,并更加灵活地满足不同用 ...
- mysql进阶(二十七)数据库索引原理
mysql进阶(二十七)数据库索引原理 前言 本文主要是阐述MySQL索引机制,主要是说明存储引擎Innodb. 第一部分主要从数据结构及算法理论层面讨论MySQL数据库索引的数理基础. ...
- 【MySQL】MySQL的执行计划及索引优化
我们知道一般图书馆都会建书目索引,可以提高数据检索的效率,降低数据库的IO成本.MySQL在300万条记录左右性能开始逐渐下降,虽然官方文档说500~800w记录,所以大数据量建立索引是非常有必要的. ...
- (转)Mysql哪些字段适合建立索引
工作中处理数据时,发现某个表的数据达近亿条,所以要为表建索引提高查询性能,以下两篇文章总结的很好,记录一下,以备后用. 数据库建立索引常用的规则如下: 1.表的主键.外键必须有索引: 2.数据量超过3 ...
- 23.Mysql应用优化
23.应用优化23.1 使用连接池应用启动时创建好连接,以供用户使用,而不是每次创建. 23.2 减少对Mysql的访问 23.2.1 避免对同一数据做重复检索合并简单查询,减少访问次数. 23.2. ...
随机推荐
- .net core 和 WPF 开发升讯威在线客服与营销系统:使用线程安全的 BlockingCollection 实现高性能的数据处理
本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 在线演示环境:https://kf.shengxunwei.com 注意 ...
- docker(9)Dockerfile制作镜像
前言 如果我们已经安装了一个python3的环境,如果另一台机器也需要安装同样的环境又要敲一遍,很麻烦,这里可以配置Dockerfile文件,让其自动安装,类似shell脚本 Dockerfile编写 ...
- 模块化之CommonJS
一.CommonJS特点 经过前面讨论,已经知道无模块化时项目中存在的问题.CommonJS的特点就是解决这些问题即: 1.每个文件都是一个单独的模块,有自己的作用域,声明的变量不是全局变量( ...
- 2019CCPC厦门站总结
这是一篇打铁游记~ $day1$ 坐动车去厦门,三个人买了一堆零食,吃了一路,除了睡觉嘴巴基本就没停过.当然,我们到酒店后也去吃了烧烤,我们虽然是在岛外的厦门北站的下的,还是很幸运的找到一家好吃了,乌 ...
- HDU6703 array (线段树)
题意:长为1e5的全排列 有两个操作 把一个数删掉 询问1,r这个区间内 找到一个数大于等于x 且这个数不等于区间内的所有数 题解:建一颗权值线段树 线段树里存值为i的数在原数组中的坐标 维护坐标的最 ...
- Scrambled Polygon POJ - 2007 极角排序
题意: 给你n个点,这n个点可以构成一个多边形(但是不是按顺序给你的).原点(0,0)为起点,让你按顺序逆序输出所有点 题解: 就是凸包问题的极角排序 用double一直Wa,改了int就可以了 // ...
- 【noi 2.6_1808】最长公共子序列(DP)
题意:给2个字符串求其最大公共子序列的长度.解法:这个和一般的状态定义有点不一样,f[i][j]表示 str 前i位和 str2 前j的最大公共子序列的长度,而不是选 str 的第i位和 str2 的 ...
- Codeforces Round #594 (Div. 2) C. Ivan the Fool and the Probability Theory (思维,递推)
题意:给你一个\(n\)x\(m\)的矩阵,需要在这些矩阵中涂色,每个格子可以涂成黑色或者白色,一个格子四周最多只能有\(2\)个和它颜色相同的,问最多有多少种涂色方案. 题解:首先我们考虑一维的情况 ...
- 2018-2019 ACM-ICPC, Asia Dhaka Regional Contest C.Divisors of the Divisors of An Integer (数论)
题意:求\(n!\)的每个因子的因子数. 题解:我们可以对\(n!\)进行质因数分解,这里可以直接用推论快速求出:https://5ab-juruo.blog.luogu.org/solution-p ...
- woj1010 alternate sum 数学 woj1011 Finding Teamates 数学
title: woj1010 alternate sum 数学 date: 2020-03-10 categories: acm tags: [acm,woj,数学] 一道数学题.简单. 题意 给一个 ...