MYSQL 索引汇总
1.MySQL索引类型
先分以下类,MYQL有两大类索引:聚集索引和非聚集索引(只考虑mysql innodb)
聚集索引:在有主键的情况下,主键为聚集索引,其他都是非聚集索引
在没有主键的情况下,使用唯一索引作为聚集索引,其他都是非聚集索引
在没有主键没有唯一索引的时候mysql创建隐藏列作为唯一索引,其他都是非聚集索引
##聚集索引叶子节点存放表的整行数据
非聚集索引,除了聚聚索引外的全部索引,下面有介绍
## 只保存索引列和主键的值(例如我我在字段 name上加一个二级普通索引,就只存在name的值和主键的值)
聚集索引索引和非聚集索引的区别: 聚集索引的逻辑顺序对应磁盘的物理顺序,也就是改变聚集索引列的值时会移动磁盘的物理位置会把该主键对应的记录的物理位置,也就是磁盘位置也更换,这样不但效率不高,可能面临页分裂的问题,当行的主键值要求必须将这一行插入到某个已满的页中时,存储引擎会将该页分裂成两个页面来容纳该行,这就是一次页分裂操作,页分裂会导致表占用更多的磁盘空间。聚集索引可能导致全表扫描变慢,尤其是行比较稀疏,或者由于页分裂导致数据存储不连续的时候。
## 疑问:关于非聚集索引的逻辑顺序不对应磁盘物理位置,也不敢肯定,以后直到了回来填坑
## 推测:非聚集索引在达到索引覆盖时(就是不用回表,在二级索引能找到值的时候),感觉会比主键要快一点(假如表的列很多的时候,聚集索引的B+tree会比非聚集索引的B+tree要高,假如一页有16K,列越多,单行数据越大,一页能放下的行数越小,从而树会比二级索引要高一些)
例如:select name from test where name='lxl' ---name是二级普通索引,就是覆盖索引,select 的列被使用的索引包含(如何看索引是否被使用--EXPLAIN,下面有说)
## 关于推测和疑问看看就好,不肯定。
主键索引
在INNODB下且有主键的情况下,数据文件和主键索引文件是同一个文件
##除叶子节点外是索引,叶子节点保存表的全部记录
创建主键索引操作:
CREATE TABLE t5 ( col1 INT NOT NULL, col2 CHAR NOT NULL, col3 INT NOT NULL, col4 INT NOT NULL, PRIMARY KEY(col1,col2) )
或者:
CREATE TABLE t5 ( col1 INT NOT NULL primary key, col2 CHAR NOT NULL, col3 INT NOT NULL, col4 INT NOT NULL )
删除主键索引:
alter table test drop primary key
##在有自增的时候,要取消自增再删除主键
alter table test modify column id
int
not
null
;
给已有列增加主键索引:
alter table test add primary key(id)
唯一索引
在没有主键的情况下,充当primary key 的角色
在有主键的情况下,跟单列索引的区别是多了个唯一约束,
叶子节点除了记录索引列的数据外还记录主键,在没有达到索引覆盖时会在辅助索引上找到该列的主键,再通过主键到数据文件(索引文件)中找到全部数据
创建唯一索引操作: CREATE TABLE t5 ( col1 INT NOT NULL, col2 CHAR NOT NULL, col3 INT NOT NULL, col4 INT NOT NULL, UNIQUE KEY(col1,col2) ) 或者: CREATE TABLE t5 ( col1 INT NOT NULL UNIQUE KEY, col2 CHAR NOT NULL, col3 INT NOT NULL, col4 INT NOT NULL ) 删除唯一索引: show index from test; ---先查看索引 +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | t9 | 0 | col1 | 1 | col1 | A | 0 | NULL | NULL | | BTREE | | | | t9 | 0 | col1_2 | 1 | col1 | A | 0 | NULL | NULL | | BTREE | | | +-------+------------+- alter table t9 drop index col1; alter table t9 drop index col2; 给现有列增加唯一索引 alter table t9 modify column col1 int not null unique key; 或者: alter table t9 add unique(col1) |
组合索引
创建组合索引: CREATE TABLE test10 ( id INT NOT NULL, last_name CHAR( 30 ) NOT NULL, first_name CHAR( 30 ) NOT NULL, PRIMARY KEY (id), INDEX name (last_name,first_name) ); 删除组合索引: show index from test10; +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | test10 | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | | test10 | 1 | name | 1 | last_name | A | 0 | NULL | NULL | | BTREE | | | | test10 | 1 | name | 2 | first_name | A | 0 | NULL | NULL | | BTREE | | | +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ alter table test10 drop index name; 给现有列增加组合索引 alter table test10 add index(last_name,first_name); |
单列索引
叶子节点除了记录索引列的数据外还记录主键,在没有达到索引覆盖时会在辅助索引上找到该列的主键,再通过主键到数据文件(索引文件)中找到全部数据
创建单列索引: CREATE TABLE test11 ( id INT NOT NULL, last_name CHAR( 30 ) NOT NULL, first_name CHAR( 30 ) NOT NULL, PRIMARY KEY (id), INDEX name (last_name) ); 删除单列索引: show index from test11; +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | test11 | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | | test11 | 1 | name | 1 | last_name | A | 0 | NULL | NULL | | BTREE | | | +--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ alter table test11 drop index name; 给现有列增加组合索引 alter table test10 add index(last_name); |
外键约束
外键加强了数据的一致性,但是
每次子表更新操作时都会对父表select 一次,
每次父表删除的时候,都对子表删除对应信息
[CONSTRAINT [symbol]] FOREIGN KEY [index_name] (col_name, ...) REFERENCES tbl_name (col_name,...) [ON DELETE reference_option] [ON UPDATE reference_option] reference_option: RESTRICT | CASCADE | SET NULL | NO ACTION | SET DEFAULT RESTRICT:拒绝父表的删除或更新操作。指定 RESTRICT(或NO ACTION)与省略ON DELETEor ON UPDATE子句相同 CASCADE:从父表中删除或更新该行,并自动删除或更新子表中的匹配行 NO ACTION: 等效于RESTRICT SET NULL:从父表中删除或更新该行,并将子表中的外键列设置为NULL SET DEFAULT:MySQL解析器可以识别此操作,但是两者都拒绝 创建外键约束 ------ 父表 ------ CREATE TABLE parent ( id INT NOT NULL, PRIMARY KEY (id) ) ENGINE=INNODB; ------ 子表 ------ CREATE TABLE child ( id INT, parent_id INT, INDEX par_ind (parent_id), FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE ) ENGINE=INNODB; 给现有表增加外键约束 ALTER TABLE test.PERSON ADD FOREIGN KEY(department_id) references test.department(id) 删除现有外键约束 show index from test.person +--------+------------+---------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +--------+------------+---------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | person | 0 | PRIMARY | 1 | id | A | 0 | NULL | NULL | | BTREE | | | | person | 1 | department_id | 1 | department_id | A | 0 | NULL | NULL | | BTREE | | | +--------+------------+---------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ ALTER TABLE tbl_name DROP FOREIGN KEY department_id; |
2.EXPLAIN
查看方法 EXPLAIN + SELECT 语句
## 执行 explain select * from test.test;
2.select_type ---查询的类型
SIMPLE --简单select,不使用UNION或者子查询, 使用连结也是simple(例如inner join)
PRIMARY --子查询中最外层查询,查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY
## 子查询中需要达到一定数据量
UNION — UNION中第二个或者后面的SELECT 语句
DEPENDENT UNION --UNION中的第二个或后面的SELECT语句,有外部的查询的情况下
UNION RESULT --UNION的结果,union语句中第二个select开始后面所有select
SUBQUERY --在select 或 where列表中包含了子查询的第一个子查询
DEPENDENT SUBQUERY --子查询中的第一个SELECT,取决于外面的查询
DERIVED --派生表的SELECT(FROM子句的子查询)
UNCACHEABLE SUBQUERY ---一个子查询,对于外面的主表,子查询结果不能被缓存,每次都要重新检索
UNCACHEABLE UNION ---UNION操作中,结果不能被缓存
3.table
显示查询的表名
如果查询使用了别名,那么显示别名
如果不涉及数据表的操作,显示null
如果显示为尖括号括起来的,表示这是一个临时表 <>
4.type
效率排序:
system > const > eq_ref > ref > range > index > all (index_merge之类的不加入效率排序,跟具体情况有关)
system ---const中的一个特例,表中只有一条记录,无论是否使用唯一索引或者主键
const ---使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type是const
eq_ref --在关联查询中使用唯一索引或者主键索引作为连接条件
ref --使用普通索引的定值查找,连接查询时使用普通索引作关联条件
range ---使用索引的范围查找
index ---遍历B+树
##Innodb存储引擎
##这里第一条达到索引覆盖,不需要回主键表读取(INNODB主键和数据是一个文件同一颗B+tree,保存所有数据),普通索引文件保存主键id以及索引那列的值,
##在mysql没达到索引覆盖的时候,mysql检索的时候认为扫表(遍历索引文件,就是遍历树的叶子节点)快一点就不去走索引了
all ----遍历B+树的叶子节点
5.possible_keys
指出MySQL在检索时能使用哪个索引,但不一定被查询使用
6.key
key列显示MySQL实际决定使用的键(索引),必然包含在possible_keys中
7.key_len
id int | key_len = 4+1 | int为4bytes,允许为NULL,加1byte |
id bigint not null | key_len=8 | bigint为8bytes |
user char(30) utf8 | key_len=30*3+1 | utf8每个字符为3bytes,允许为NULL,加1byte |
user varchar(30) not null utf8 | key_len=30*3+2 | utf8每个字符为3bytes,变长数据类型,加2bytes |
user varchar(30) utf8 | key_len=30*3+2+1 | utf8每个字符为3bytes,允许为NULL,加1byte,变长数据类型,加2bytes |
列类型
|
KEY_LEN
|
备注
|
---|
mysql检索数据时所使用索引的长度
使用的索引的长度。在不损失精确性的情况下,长度越短越好
用于计算组合索引中用到了几个索引
8.ref
如果是使用的常数等值查询,这里会显示const
如果是连接查询,被驱动表的执行计划这里会显示驱动表的关联字段
如果是条件使用了表达式或者函数,或者条件列发生了内部隐式转换,这里可能显示为func。
================== rows =================
这里是执行计划中估算的扫描行数,不是精确值
================== extra ==================
distinct --在找到第一匹配的元组后即停止找同样值的动作
no table used ----不带from的select 语句,或者使用了from dual
using filesort ---MySQL必须额外进行一遍,同时使用不到索引
using index --索引覆盖,不需要回表查询
using temporapy ---查询中使用了临时表作为中间结果
using where ---使用了where条件
using interset ---index-merge时,表示使用and的各个索引的条件时,该信息表示是从处理结果获取交集
using union: ---表示使用or连接各个使用索引的条件时,该信息表示从处理结果获取并集
3 一条SQL在使用索引的时候是怎么找的
================== 从B+tree角度分析 ========================
在Innodb存储引擎中
1.每新增一个索引,就会增加一个索引文件,保存在data目录的对应数据库中
2.索引文件实质是一个B+tree结构
##假如给一个表的一个字段建立一个辅助索引,索引保存的该字段数据为 1,2,3,5,6,8,9,11,13,15
3.假如要找的数据为3(where 该字段=3)
第一次磁盘IO为(8,15)的的节点
第二次磁盘IO为(2,5,8)的节点
第三次磁盘IO为(3,5)的节点
所以要找到3这个数据大概3次磁盘IO
当然,也不是说查找这个3 要等待3次磁盘IO,
根据局部性原理于磁盘预读
由于存储介质的特性,磁盘本身存取就比主存慢很多,再加上机械运动耗费,磁盘的存取速度往往是主存的几百分分之一,因此为了提高效率,要尽量减少磁盘I/O。为了达到这个目的,磁盘往往不是严格按需读取,而是每次都会预读,即使只需要一个字节,磁盘也会从这个位置开始,顺序向后读取一定长度的数据放入内存
###在没有索引的时候,如果一般where 字段=30
在where的字段没有索引的情况,会根据这个链表的顺序从头遍历下去,直到找到30。
ps:在B+tree中叶子节点形成一个链表
ps:在Innodb下,数据文件也是一颗B+树
ps: 别以为二层索引就放这几条数据,假如一个页16K,二级索引一个索引列(索引列+主键值)为10B,然后一个节点就能放1600个索引列,二层索引结构,叶子节点就有1600^3,然后每个叶子节又有1600个索引列,就是能放1600^4个索引列
4 如何设计索引?
1.根据索引的选择性来建立索引 ---是指不重复的索引值(也叫基数,Cardinality)与表记录数(#T)的比值:Index Selectivity = Cardinality / #T
选择性越高的索引价值越大 ,SELECT count(DISTINCT(name))/count(*) AS Selectivity FROM test.test;
###有一种与索引选择性有关的索引优化策略叫做前缀索引----用列的前缀值代替整个列作为索引key,当前缀长度合适时,可以做到前缀索引的选择性接近全列索引,同时因为索引长度减少了从而减少索引文件的开销和维护。
###虽然前缀索引兼顾索引大小和查询速度,但是其缺点是不能用于order by 和group by。也不能用于索引覆盖
2.(待完善)
MYSQL 索引汇总的更多相关文章
- MySQL查询不使用索引汇总 + 如何优化sql语句
不使用索引原文 : http://itlab.idcquan.com/linux/MYSQL/918330.html MySQL查询不使用索引汇总 众所周知,增加索引是提高查询速度的有效途径,但是很多 ...
- MySQL笔记汇总
[目录] MySQL笔记汇总 一.mysql简介 数据简介 结构化查询语言 二.mysql命令行操作 三.数据库(表)更改 表相关 字段相关 索引相关 表引擎操作 四.数据库类型 数字型 字符串型 日 ...
- Mysql数据库知识-Mysql索引总结 mysql mysql数据库 mysql函数
mysql数据库知识-Mysql索引总结: 索引(Index)是帮助MySQL高效获取数据的数据结构. 下边是自己整理的资料与自己的学习总结,,做一个汇总. 一.真的有必要使用索引吗? 不是每一个性能 ...
- 单表扫描,MySQL索引选择不正确 并 详细解析OPTIMIZER_TRACE格式
单表扫描,MySQL索引选择不正确 并 详细解析OPTIMIZER_TRACE格式 一 表结构如下: 万行 CREATE TABLE t_audit_operate_log ( Fid b ...
- mysql性能优化-慢查询分析、优化索引和配置 MySQL索引介绍
MySQL索引介绍 聚集索引(Clustered Index)----叶子节点存放整行记录辅助索引(Secondary Index)----叶子节点存放row identifier-------Inn ...
- Mysql高手系列 - 第22篇:深入理解mysql索引原理,连载中
Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第22篇. 背景 使用mys ...
- mysql索引设计的注意事项
mysql索引设计的注意事项 目录 一.索引的重要性 二.执行计划上的重要关注点 (1).全表扫描,检索行数 (2).key,using index(覆盖索引) (3).通过key_len确定究竟使用 ...
- MySQL索引与事务
MySQL索引与事务 链接:https://pan.baidu.com/s/1ANGg3Kd_28BzQrA5ya17fQ 提取码:ekpy 复制这段内容后打开百度网盘手机App,操作更方便哦 1.索 ...
- mysql索引的面试题
相信很多人对于MySQL的索引都不陌生,索引(Index)是帮助MySQL高效获取数据的数据结构. 因为索引是MySQL中比较重点的知识,相信很多人都有一定的了解,尤其是在面试中出现的频率特别高.楼主 ...
随机推荐
- vagrant 入门案例 - 快速创建 Centos7
中文文档:http://tangbaoping.github.io/vagrant_doc_zh/v2/ 参考: https://blog.csdn.net/yjk13703623757/articl ...
- HTML+CSS:css定位详解之相对定位、绝对定位和固定定位
相对定位 如果想为元素设置层模型中的相对定位,需要设置position:relative;,它还是会占用该元素在文档中初始的页面空间,通过left.right.top.bottom属性确定元素在正常文 ...
- 1041 Be Unique (20分)(水)
Being unique is so important to people on Mars that even their lottery is designed in a unique way. ...
- 【PHP】PHP基本语法
一.什么是PHP? a) 定义:PHP就是超文本预处理器 b) 超文本:我们前边8天学习的内容其实就是超文本内容 c) 预处理器:相当于牛奶在工厂加工的过程,我们虽然不可见,但是我们 ...
- Java并发编程实战 01并发编程的Bug源头
摘要 编写正确的并发程序对我来说是一件极其困难的事情,由于知识不足,只知道synchronized这个修饰符进行同步. 本文为学习极客时间:Java并发编程实战 01的总结,文章取图也是来自于该文章 ...
- React Native简史
诞生 React Native 诞生于 2013 年的 Facebook 内部黑客马拉松(hackathon): In the essence of Facebook’s hacker culture ...
- git配置用户名
git config --global user.name [name] git config --global user.email [email_address]
- Java的运行时数据存储机制
原文地址:http://yanwushu.sinaapp.com/java_data_storage/ Java程序在运行时需要为一系列的值或者对象分配内存,这些值都存在什么地方?用什么样的数据结构存 ...
- 曹工说Redis源码(6)-- redis server 主循环大体流程解析
文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis,而怎么才能懂,光看是不够的,建议跟着下面的这一篇,把环境搭建起来,后续可以自己阅读源码,或者跟着我这边一起阅读.由于 ...
- jmeter if控制器使用
if控制器有两种用法 1.不勾选“interpret condition as variable expression” 直接输入我们需要判断的表达式即可,判断表达式为真时,执行if控制器下的请求 2 ...