Mysql的存储引擎与索引

52 阅读12分钟

跟孙哥学java

孙哥主页

存储引擎

存储引擎简介

存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表的,而不是基于库的,所以存储引擎也可被称为表类型。 查询表的存储引擎,通过查询建表语句

show create table user;

image.png --查询当前数据库支持的存储引擎:

show engines;

image.png

--创建一个以MyISAM存储引擎的表
create table my_myisam(
    id int,
    name varchar(10)
) engine =MyISAM;

show create table my_myisam;
--创建一个以MEMORY存储引擎的表
create table my_memory(
                          id int,
                          name varchar(10)
) engine =MEMORY;

:::info 1.在创建表时,指定存储引擎 CREATE TABLE表名( 字段1字段1类型[COMMENT字段1注释], 5595: 字段n字段n类型 [COMMENT字段n注释] )ENGINE=INNODB[COMMENT表注释] 2.查看当前数据库支持的存储引擎 SHOW ENGINES :::

存储引擎特点

InnoDB

  1. 介绍

InnoDB是一种兼顾高可靠性和高性能的通用存储引擎,在MySQL5.5之后,InnoDB是默认的MySQL存储引擎。

  1. 特点

DML操作遵循ACID模型,支持事务行级锁,提高并发访问性能: 支持外键FOREIGN KEY约束,保证数据的完整性和正确性;

  1. 文件

XXX.ib:xx代表的是表名,innoDBi引擎的每张表都会对应这样一个表空间文件,存储该表的表结构(frm、sdi)、数据和索引。 image.png 参数:innodb_file_per_table image.png MyISAM

介绍 MyISAM是MySQL早期的默认存储引擎。 特点 不支持事务,不支持外键 支持表锁,不支持行锁 访问速度快 文件 Xx.sdi:存储表结构信息 Xx.MYD:存储数据 Xx.MYI:存储索引 Memory 介绍 Memoryi引擎的表数据时存储在内存中的,由于受到硬件问题、或断电问题的影响,只能将这些表作为临时表或缓存使用。 特点 内存存放 hash索引(默认)】 文件 x.sdi:存储表结构信息 image.png

存储引擎选择

在选择存储引擎时,应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组 合。

InnoDB:是Mysql的默认存储引擎,支持事务、外键。如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包含很多的更新、删除操作,那么InnoDB存储引擎是比较合适的选择。 MyISAM:如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高,那么选择这个存储引擎是非常合适的。 MEMORY:将所有数据保存在内存中,访问速度快,通常用于临时表及缓存。MEMORY的缺陷就是对表的大小有限制,太大的表无法缓存在内存中,而且无法保障数据的安全性。

总结

image.png

索引

索引概述

介绍

索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

演示

image.png

优缺点

image.png

索引结构

MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的结构,主要包含以下几种: image.png image.png 一般默认就是B+tree索引 image.png 所有数据都会出现在叶子节点 叶子节点形成一个单向列表 image.png image.png 为什么InnoDB存储引擎选择使用B+tree索引结构?

相对于二叉树,层级更少,搜索效率高; 对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一 页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的 高度,导致性能降低; 相对Hash索引,hash索引只支持等值匹配,B+tree支持范围匹配及排序操作;

索引分类

image.png

image.png 聚集索引,叶子节点保存了一行的数据,而二级索引,存储的是主键的索引 image.png 思考? image.png 第一条语句的效率高,因为第一条只需要到聚集索引去找到行数据 而第二条数据需要先走name的二级索引查找对应的id值,再到聚焦索引去找行数据,需要回表查询 image.png 每一个节点都是存储在一个页中 image.png 高度为2: n8+(n+1)6=161024 (16k,一页) n=1170 它能够存储的数据量为 117116=18736 高度为3:11711171*16=21939856

索引语法

  • 创建索引

CREATE [UNIQUE| FULLTEXT] INDEX index_name ON table_name index_col_name,...)

  • 查看索引

SHOW INDEX FROM table name

  • 删除索引

DROP INDEX index name ON table_name

image.png

show index from b_user;
--常规索引
create index idx_user_name on b_user(user_name);
--唯一索引
create unique index   idx_money on b_user(money);
--联合索引
create index idx_user_name_money on b_user(user_name,money);

create index idx_user_meail on tb_user(email);
--删除索引
drop index idx_money on b_user;

SQL性能分析

  • SQL执行频率

MySQL客户端连接成功后,通过show[sessionlglobal]status命令可以提供服务器状态信息。通过如下指令,可以查看当前数据库的 INSERT、UPDATE、DELETE、SELECT的访问频次 : SHOW GLOBAL STATUS LIKE 'Com_______'; image.png

  • 慢查询日志

慢查询日志记录了所有执行时间超过指定参数(long_query_.time,单位:秒,默认10秒)的所有SQL语句的日志。 MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息: image.png 默认关闭 image.png vi /etc/my.cnf image.png

  • profile详细

show profiles能够在做SQL优化时帮助我们了解时间都耗费到哪里去了。通过nave profiling参数,能够看到当前MySQL是否支持 image.png 默认profile是关闭的 image.png 开启profile image.png

profile操作: image.png

  • explain执行计划

image.png EXPLAIN或者DESC命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。

image.png 查询所有学生的选课情况 image.png 查看执行顺序: image.png 查询选修了MYSQL课程的学生(子查询) select _* _from student s where s.id in(select sc.studentid from student_course sc where sc.courseid= (select id from course c where c.name='MySQL')); image.png image.png 的代表内部子查询

不访问任何表它的连接类型才是null image.png

语法: #直接在selecti语句之前加上关键字explain/deC EXPLAIN SELECT字段列表FROM表名WHERE条件;

Id selecti查询的序列号,表示查询中执行select-子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越先执行)。 select_type 表示SELECT的类型,常见的取值有SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、 UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(SELECT./WHERE之后包含了子查询)等 type 表示连接类型,性能由好到差的连接类型为NULL、system、const(主键/唯一索引)、eq_ref、ref(非唯一性索引)、range、index、all。 possible key 显示可能应用在这张表上的索引,一个或多个。 Key 实际使用的索引,如果为NULL,则没有使用索引。 Key_len 表示索引中使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好。 rows MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的。 filtered 表示返回结果的行数占需读取行数的百分比,filtered的值越大越好。

索引使用

最左前缀原则

image.png 对于tb_user ,的联合索引 profession,age,status ,若最左边的列 profession不存在,索引就全部失效了 image.png

若跳跃了某一列,索引会部分失效 image.png image.png

索引的最左字段只要存在,就会生效,跟查询的顺序无关 image.png

范围查询:

联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效 explain selectfrom tb_user where profession='软件工程'and age>30 and status='0'; 索引长度为49,导致 age的索引失效了 image.png 如何规避索引失效呢?? explain selectfrom tb_user where profession='软件工程'and age>=30 and status='0'; image.png 把>,<改成>= <=

索引失效的情况

  1. 不要在索引列上进行运算操作, 索引将失效。

explain select * from tb_user where phone = '17799990015'; image.png 使用了单列索引 explain select * from tb_user where substring(phone,10,2) = '15'; image.png 并没有使用phone索引,因为对索引列进行了函数运算

  1. 字符串类型的字段没有加' ';

explain select * from tb_user where phone = 17799990015; image.png explain select * from tb_user where phone = '17799990015'; image.png

  1. 模糊查询

如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。 等值匹配 image.png 模糊匹配 尾部模糊匹配 image.png 模糊匹配 头部模糊匹配 image.png 前后都模糊匹配,也失效 image.png

  1. OR连接的条件

用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。 explain select * from tb_user where id=10 and age=23; explain select * from tb_user where phone ='17799990017'or age=23; image.png 给age建立索引 ,再次使用查询or image.png 索引生效了

  1. 数据分布影响

image.png 当我们把电话改成最小的电话 image.png 就不走索引了,这是因为所有的表的数据都是 >=这个电话号,就走了全表扫描

image.png

image.png 这说明了如果走索引查询慢就不会走索引 走不走索引取决于当前数据库的数据分布情况

SQL提示

SQL提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。 image.png 给profession添加索引 image.png 发现还是走的联合索引,没有走单列索引 我们可以建议sql走哪一个索引 (mysql内部会进行评估,可能不会接收你的建议) explain select *from tb_user use index(idx_user_pro) where profession='软件工程'; image.png 忽略某个索引: explain select *from tb_user ignore index(idx_user_pro) where profession='软件工程'; image.png 强制某一个索引: explain select *from tb_user force index(idx_user_pro) where profession='软件工程'; image.png

覆盖索引

尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到),减少select*。

explain select * from tb_user where profession ='软件工程’and age=31 and status ='0'; image.png

explain select id,profession,age,status from tb_user where profession='软件工程' and age=31 and status='0'; image.png

:::info 知识小贴士: NULL:查找使用了索引,但是需要回表查询数据 using index:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据 :::

image.png 给username 和password 建立联合索引,不需要走回表查询了,直接覆盖查询

前缀索引

当字段类型为字符串(varchar,text等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘O,影响查询效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。

语法: create index idx_xxxx on table_name(column(n)) ;

前缀长度: 可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高, 唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。 select count(distinct email)/count(*) from tb_user; image.png image.png image.png 创建索引 email ,前五个数据的 索引 image.png image.png 长字符串和文本比较长的时候,可以考虑使用前缀索引,降低索引的体积,提高查询的效率

单列索引和联合索引

单列索引:一个索引只包含单个列,单个字段 联合索引:一个索引包含多个列,多个字段

有name和phone两个单列索引进行查询,只走了phone索引 image.png

给它创建联合索引 image.png :::info 在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,而非单列索引。 :::

索引设计原则

:::info 1). 针对于数据量较大,且查询比较频繁的表建立索引。 2). 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。 3). 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。 4). 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。 5). 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。 6). 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。 7). 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。 :::