Mysql进阶-索引事务相关

数据库存储引擎

1.创建表时,指定存储引擎
注意存储引擎是以表为单位的

CREATE TABLE table_name (
		字段1  字段1类型
		....
)ENGINE = INNODB;

不指定 ENGINE = INNODB,mysql5.5版本以上默认就是INNODB

2.查看当前数据库支持哪些存储引擎

show engines;

INNODB

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

特点

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

文件
xxx.idb: xxx代表的是表名,innoDB引擎的每张表都会对应这样的一个表空间文件,存储该表的表结构(frm、sdi)、数据和索引。
可以在存放表空间文件的目录下打开cmd,然后运行 ibd2sdi xxxx.idb,就可以查看这个表空间文件的sdi数据

MYISAM
  • 早些年使用,节约空间,速度快
MYISAMINNODB
事务支持不支持支持
数据行锁定不支持支持
外键约束不支持支持
全文索引支持不支持
表空间大小较小较大,约2倍

文件
xxx.sdi: 存储表结构信息
xxx.MYD:存储数据
xxx.MYI:存储索引

对于数据的一致性要求高,是重要的数据,要求事务的就选用innodo引擎,对数据的一致性要求不高,偶尔丢失一两条数据也没关系的,例如日志信息,足迹信息等,就可以选用Myisam引擎(但目前市场上该需求主要被mangodb代替了)

索引

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

  • 索引的优缺点
    在这里插入图片描述

  • 索引结构
    在这里插入图片描述

  • B+Tree索引
    MySQL索引数据结构对经典的B+Tree进行了优化,在原B+Tree的基础上,增加了一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问性能
    在这里插入图片描述
    B+Tree只在叶子节点存储数据,而BTree在叶子和非叶子都存储数据

  • Hash索引
    1.Hash索引只能用于对等比较(=,in),不支持范围查询(between,>, <, …)
    2.无法利用索引完成排序操作
    3.查询效率高,通常只需要一次检索就可以了,效率通常要高于B+Tree索引

    Hash索引只有Memory引擎支持

为什么InnoDB存储引擎选择使用B+tree索引结构?

  1. 相对于二叉树,层级更少,搜索效率高;
  2. 对于B-tree,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一页存储的键值减少,指针跟着减少,要保存同样大量的数据,只能增加树的高度,(而树当中不同层的页可能存放在磁盘不同的位置上,这样就需要多次I/O读取,大大消耗性能),导致性能降低;
  3. 相对Hash索引,B+tree支持范围匹配即排序操作(B+tree的叶子节点种形成了双向链表,便于范围搜索和排序

索引分类

在这里插入图片描述

Innodb引擎的聚簇索引(主键索引)的叶子节点上存放的是数据本身,而MyISAM引擎(默认非聚簇索引)的聚簇索引和非聚簇索引(二级索引,辅助索引)的叶子节点存放的是指向数据的物理地址

聚集索引也叫聚簇索引
一般会用主键构建聚集索引,叶子节点中除了主键值,还有这条数据的具体信息;而二级索引就是用户自己增加的唯一索引,普通索引这种,它们都是采用B+tree的数据结构存储,但二级索引的叶子节点存储的是这个字段以及主键值
在这里插入图片描述
InnoDB主键索引的B+tree高度为多高呢
假设:一行数据的大小为1k,一页中可以存储16行这样的数据。InnoDB的指针占用6个字节的空间,主键即使为bigint,占用字节数8
在这里插入图片描述
因此数据如果大概超过2000w的数量级,需要开始考虑分库分表

索引语法

create index 索引名 on 表名(字段名);
create unique index 索引名 on 表名(phone);
create index 索引名 on 表名(字段1,字段2,字段3);
drop index 索引名 on 表名;
show index from 表名 (查询表的全部索引)

SQL性能分析

SQL执行频率

show global status like ‘Com_______’;

可以查看当前数据库的insert、update、delete、select的访问频次
在这里插入图片描述

慢查询

慢查询日志记录了所有执行时间超过指定参数(long_query_time, 单位:秒,默认10秒)的所有SQL语句的日志。
MySQL的慢查询日志默认没有开启

show variables like ‘slow_query_log’;查看是否有开启
SHOW VARIABLES LIKE ‘long_query_time’; 查看慢查询阈值

开启MySQL慢日志查询开关
set global slow_query_log=1;
这种开启慢查询日志只对当前数据库生效,如果MySQL重启则失效。
若想永久生效,久必须修改配置文件my.cnf, [mysqld]下增加或修改参数如下:

[mysqld] 
slow_query_log=1 
slow_query_log_file=/var/lib/mysql/atguigu-slow.log 
long_query_time=3 
log_output=FILE

设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
set global long_query_time=2

log_queries_not_using_indexs
这也是慢查询日志中的一个参数,如果允许的SQL语句没有使用索引,则Mysql数据库同样会将该条sql语句记录到慢查询日志文件中。

show variables like ‘log_queries_not_using_indexes’\G; 查看是否打开了该参数

MySQL 5.6.5版本开始新增了一个参数log_throttle_queries_not_using_indexes,用来表示每分钟允许记录到 slow log(Mysql 5.1开始可以将慢查询日志记录放入到一张slow_log表中)的且未使用索引的SQL语句次数,默认值未0,表示没有限制。

但是随着日志的不断增加,后续要分析日志将会变得不那么直观。可以通过mysqldumpslow命令

mysqldumpslow -s al -n 10 david.log;获取执行时间最长的10条SQL语句

profile详情

执行一系列的业务SQL的操作,然后通过如下指令查看指令的执行耗时:

 # 查看每一条SQL的耗时基本情况
 show profiles;
# 查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;

# 查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;

explain 执行计划

在这里插入图片描述

explain select xxxxx 或者 desc select xxx 可以查询这个查询语句的执行计划,具体参数含义如下:

  • id
    select 查询的序列号,表示查询中执行select子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越先执行)。
  • select_type
    表示SELECT的类型,常见的取值有SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(SELECT/WHERE之后包含了子查询)等
  • type
    表示连接类型,性能由好到差的连接类型为NULL、system、const、eq_ref、ref、range、index、all。
    一般select不访问表的时候才会为NULL,因此在实际业务中不太可能优化到NULL
    使用主键/唯一索引作为查询条件,那么连接类型为const,不是唯一索引连接类型为ref,
    index:【index】会遍历索引树,index回避ALL速度快一些,但是任然有使用不对的地方
  • possible_key
    显示可能应用在这张表上的索引,一个或多个
  • key
    实际使用的索引,如果为NULL,则没有使用索引
  • Key_len
    表示索引中使用的字节数,该值为索引字段最大的可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好
  • rows
    MySQL认为必须要执行查询的行数,在innodb引擎的表中,是一个估计值,可能并不总是准确的
  • filtered
    表示返回结果的行数占需读取行数的百分比,filtered的值越大越好
Etrax(额外信息)
using index condition

查找使用了索引,但是需要回表查询数据

using where;using index

Using index 和 Using where 的同时出现表示查询利用了索引加速数据检索,并在索引扫描后使用了额外的条件过滤来获取最终的结果。这通常是一个相对高效的执行计划,但仍然需要考虑索引的选择性、数据量和其他查询条件对性能的影响。
重点例子

在这里插入图片描述
该表是有 age_name的联合索引,没有单独的name索引,这里的where只用了 name字段
不符合最左前缀法则,但通过Extra得知任然使用了索引,而type又为index,所以真实是走了索引,但是因为缺少联合索引的最左字段age,没有了顺序,因此它是遍历了索引树,根据name的条件找到了数据,所以Extra中还有Using where,因为该表只有三个字段 id,age,name ,所以该联合索引的目标叶子节点上有需要的所有数据,不再需要回表,

using where

该属性与using index相反,查询的列并没有被索引覆盖,需用用未建立索引的字段进行数据过滤,有两种情况
1.where name = 1 ,name字段并没有设置索引(因此没走索引,走全表,但又需要用name进行过滤
2.where name > 1, 由于数据分布,导致mysql最终没有选择走索引(nam>1的数据选择性太高,优化器认为走全表扫描更快)也是没走索引,走全表,但也需要name字段进行过滤

索引使用规则

最左前缀法则

如果索引了多列(联合索引),要遵守最左前缀法则,最左前缀法则指的是查询从索引最左列开始,并且不能跳过索引中的列。 最左的列只需要存在即可,顺序可以不按照索引顺序
如果跳跃某一列,索引将部分失效(后面的字段索引失效)

范围查询

联合索引中,出现范围查询(>,<),范围查询右侧的索引失效
可以用 >= 的方式来让右侧的索引不失效
在这里插入图片描述

索引失效情况

1.索引列运算

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

explain select * from tb_user where substring(phone, 10, 2) = ‘15’;

2.字符串不加引号

字符串类型字段使用时,不加引号,依然能查询到数据,但是索引将失效

explain select * from tb_user where phone = 17799990015;

3.模糊查询

如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。

4.or连接的条件

用or分隔开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到,只有两个都有索引才会走索引
如果or前后的两个字段是联合索引,依然不会走索引,and的时候才会走

5.and连接

如果and连接的两个字段 a,b都是单列索引,那么mysql将只走一个索引,or的时候则两个都会走

6.数据分布影响

如果MySQL评估使用索引比全表更慢,则不使用索引。(如果要查询的数据占全数据的大部分则则全表,否则走索引
同理,is null 和 is not null也会根据实际该字段的数据分布,如果大部分都是null,则 is null不走索引,反之

select * from tb_user where phone >= ‘17799990005’; 走全表扫描
select * from tb_user where phone >= ‘17799990015’; 走索引

SQL提示(修改使用的索引)

SQL提示,是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。
1.use index:
建议使用索引,sql可能不接受

explain select * from tb_user use index(索引名) where profession = ‘xxxx’;

2.ignore index
忽略 该索引

3.force index
强制使用该索引

前缀索引

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

create index 索引名 on 表名(字段名(截取的位数));

前缀长度
可以根据索引的选择性来决定,而选择性是指不重复的索引值和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性是1.

select count(distinct email) / count() from tb_user; 查询去重的email数量占总数的多少,如果为1代表 唯一
select count(distinct substring(email, 1 , 5))/ count(
) from tb_user; 截取email从1开始的5个字符,并去重后占总数的多少

索引设计原则

在这里插入图片描述

并发事务带来的影响

  • 脏读

事务A,读取到了事务B还未提交的更改后的数据

  • 不可重复度

事务A,读取到了事务B已经提交了的数据,和之前读取未提交的数据不一致,导致了不可重复读

  • 幻读

事务A查询不到某条数据,但是插入该条数据就会报错已存在

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

事务隔离级别

在这里插入图片描述
READ UNCOMMITTED(读未提交):事务中的修改即使未提交也是对其它事务可见
READ COMMITTED(读提交):事务提交后所做的修改才会被另一个事务看见,可能产生一个事务中两次查询的结果不同。
REPEATABLE READ(可重读):只有当前事务提交才能看见另一个事务的修改结果。解决一个事务中两次查询的结果不同的题。
SERIALIZABLE(串行化):只有一个事务提交之后才会执行另一个事务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值