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. ...
随机推荐
- GLIBC升级
GLIBC升级 1.安装 1.1 说明 目前大部分架构都已经是GLIBC2.14了,难免会有一些老的机器会是GLIBC2.12,所以下面是我升级GLIBC的过程及步骤. GLIBC是系统核心服务,升级 ...
- k8s 调度 GPU
最近公司有项目想在 k8s 集群中运行 GPU 任务,于是研究了一下.下面是部署的步骤. 1. 首先得有一个可以运行的 k8s 集群. 集群部署参考 kubeadm安装k8s 2. 准备 GPU 节点 ...
- MiniProfiler性能分析工具— .Net Core中用法
前言: 在日常开发中,应用程序的性能是我们需要关注的一个重点问题.当然我们有很多工具来分析程序性能:如:Zipkin等:但这些过于复杂,需要单独搭建. MiniProfiler就是一款简单,但功能强大 ...
- Educational Codeforces Round 67 E.Tree Painting (树形dp)
题目链接 题意:给你一棵无根树,每次你可以选择一个点从白点变成黑点(除第一个点外别的点都要和黑点相邻),变成黑点后可以获得一个权值(白点组成连通块的大小) 问怎么使权值最大 思路:首先,一但根确定了, ...
- Codeforces Round #651 (Div. 2) D. Odd-Even Subsequence(二分)
题目链接:https://codeforces.com/contest/1370/problem/D 题意 给出一个含有 $n$ 个数的数组 $a$,从中选出 $k$ 个数组成子序列 $s$,使得 $ ...
- 2019牛客多校 Round3
Solved:3 Rank:105 治哥出题了 我感动哭了 A Graph Game (分块) 题意:1e5个点 2e5条边 s(x)表示与x点直接相邻的点集合 有两种操作 1种将按输入顺序的边第l条 ...
- Codeforces Round #697 (Div. 3) G. Strange Beauty (DP,数学)
题意:给你一组数,问你最少删去多少数,使得剩下的数,每个数都能整除数组中其它某个数或被数组中其它某个数整除. 题解:我们直接枚举所有因子,\(dp[i]\)表示\(i\)在数组中所含的最大因子数(当我 ...
- 001、Python数据结构
#! usr/bin/env python # _*_ coding:utf-8 _*_ from random import randint ''' 一.list的增删改查 1.list.appen ...
- CF1471-C. Strange Birthday Party
CF1471-C. Strange Birthday Party 题意: 你要举办一场生日派对.派对有\(n\)个人,每个人都有一个数字\(k_i\).超市有\(m\)件礼物,购买每件礼物需要花费\( ...
- Chapter Zero 0.2.3 显示适配器
显示适配器(Video Graphics Array,VGA) 不看后悔!!深入了解显卡!!!走你! 我们常常会调试显示器的分辨率,一般对于图像的显示重点在于分辨率与颜色深度, 每个图像显示的颜色会占 ...