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 索引汇总的更多相关文章

  1. MySQL查询不使用索引汇总 + 如何优化sql语句

    不使用索引原文 : http://itlab.idcquan.com/linux/MYSQL/918330.html MySQL查询不使用索引汇总 众所周知,增加索引是提高查询速度的有效途径,但是很多 ...

  2. MySQL笔记汇总

    [目录] MySQL笔记汇总 一.mysql简介 数据简介 结构化查询语言 二.mysql命令行操作 三.数据库(表)更改 表相关 字段相关 索引相关 表引擎操作 四.数据库类型 数字型 字符串型 日 ...

  3. Mysql数据库知识-Mysql索引总结 mysql mysql数据库 mysql函数

    mysql数据库知识-Mysql索引总结: 索引(Index)是帮助MySQL高效获取数据的数据结构. 下边是自己整理的资料与自己的学习总结,,做一个汇总. 一.真的有必要使用索引吗? 不是每一个性能 ...

  4. 单表扫描,MySQL索引选择不正确 并 详细解析OPTIMIZER_TRACE格式

    单表扫描,MySQL索引选择不正确 并 详细解析OPTIMIZER_TRACE格式     一 表结构如下:  万行 CREATE TABLE t_audit_operate_log (  Fid b ...

  5. mysql性能优化-慢查询分析、优化索引和配置 MySQL索引介绍

    MySQL索引介绍 聚集索引(Clustered Index)----叶子节点存放整行记录辅助索引(Secondary Index)----叶子节点存放row identifier-------Inn ...

  6. Mysql高手系列 - 第22篇:深入理解mysql索引原理,连载中

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第22篇. 背景 使用mys ...

  7. mysql索引设计的注意事项

    mysql索引设计的注意事项 目录 一.索引的重要性 二.执行计划上的重要关注点 (1).全表扫描,检索行数 (2).key,using index(覆盖索引) (3).通过key_len确定究竟使用 ...

  8. MySQL索引与事务

    MySQL索引与事务 链接:https://pan.baidu.com/s/1ANGg3Kd_28BzQrA5ya17fQ 提取码:ekpy 复制这段内容后打开百度网盘手机App,操作更方便哦 1.索 ...

  9. mysql索引的面试题

    相信很多人对于MySQL的索引都不陌生,索引(Index)是帮助MySQL高效获取数据的数据结构. 因为索引是MySQL中比较重点的知识,相信很多人都有一定的了解,尤其是在面试中出现的频率特别高.楼主 ...

随机推荐

  1. SQL Server中STATISTICS IO物理读和逻辑读的误区

    SQL Server中STATISTICS IO物理读和逻辑读的误区 大家知道,SQL Server中可以利用下面命令查看某个语句读写IO的情况 SET STATISTICS IO ON 那么这个命令 ...

  2. Step by Step!教你如何在k3s集群上使用Traefik 2.x

    本文来自边缘计算k3s社区 作者简介 Cello Spring,瑞士人.从电子起步,拥有电子工程学位.尔后开始关注计算机领域,在软件开发领域拥有多年的工作经验. Traefik是一个十分可靠的云原生动 ...

  3. Aactivity跳转到Bactivity之后再返回Aactivity的几种操作

    一个主界面(主Activity)通过意图跳转至多个不同子Activity上去,当子模块的代码执行完毕后再次返回主页面,将子activity中得到的数据显示在主界面/完成的数据交给主Activity处理 ...

  4. matplotlib TransformWrapper

    2020-04-09 23:26:53 --Edit by yangray TransformWrapper 是Transform的子类, 支持在运行中替掉一个变换(可以是不同类型, 但维度必须相同) ...

  5. Powershell如何制定属性并输出

    这个标题看着有些云里雾里.... 前一阵,群里有个朋友问博主“我想把所有用户的SMTP地址全部输出到CSV文件中进行统计,但是SMTP地址似乎输出的是错误的,可在shell里看输出的内容是正确的阿” ...

  6. syncronized如何上锁

    上锁,根据操作系统所说的原则,对共享变量上锁,对临界区上锁.谁访问临界资源?就给谁上锁 同步监视器,它上锁的对象. 1.用关键字给方法上锁 2.用synchronized代码块上锁 默认上锁对象:th ...

  7. AJ学IOS(17)UI之纯代码自定义Cell实现新浪微博UI

    AJ分享,必须精品 先看效果图 编程思路 代码创建Cell的步骤 1> 创建自定义Cell,继承自UITableViewCell 2> 根据需求,确定控件,并定义属性 3> 用get ...

  8. E. Max Gcd

    单点时限: 2.0 sec 内存限制: 512 MB 一个数组a,现在你需要删除某一项使得它们的gcd最大,求出这个最大值. 输入格式 第一行输入一个正整数n,表示数组的大小,接下来一行n个数,第i个 ...

  9. SQL入门,就这么简单

    随着时代的发展,人类活动产生的信息越来越多,大家常说,现在这个时代是大数据时代.在这样一个前提下,数据的存储成为我们必须要认真对待和研究的问题了.SQL(Structured Query Langua ...

  10. Laravel项目Linux服务器部署

    laravel项目本地开发,一切正常.部署到服务器,首页都加载不出来,查了n多教程,各种方法姿势都试过了,还是不行. 功夫不负有心人,最后终于找到了问题所在,在此做个记录,铭记教训. 排查错误一定要: ...