mysql 分为4层结构:
连接层:负责处理链接,鉴权,安全。
服务层:负责sql接口,sql分析,sql优化,sql缓存。
引擎层:负责执行服务层的操作,不同的引擎拥有不同的特性。(索引在该层)
存储层:将数据存储到文件上。
输入 show engine; 可以查询到mysql 支持的存储引擎:
目前只有 InnoDB 支持 事务 。
mysql 5.5之后默认使用的就是 innoDB
想设置其他引擎可以在创建表时末尾设置 engin = xxxx:
InnoDb:默认的引擎,如果需要支持事务和外键,那就是唯一的选择。
MyISAM: 读取速度快,更新速度慢,不支持事务,已经被 mogoDB取代。
Memory:数据只存在内存中,已经被redis 取代。
一、什么是数据库索引:
索引(index)是帮助数据库提高获取数据效率的数据结构
例如:下面的数据为例,当要查找45时。如果全文检索,从上到下需要比对7次,如果二叉树索引只需要2步就差查询到结果。
索引的数据结构
数据结构的特点
数据结构的进化:
1、二叉树: 顺序插入时,会导致层级较深。
2、红黑树:(平衡二叉树)会自平衡,但是在大数据量情况下,层级也会很深。
3、B-tree (多路平衡查找树)下面的例子是 5阶的B-tree,B树的缺点是,顺序查找速度慢。
4、B+树(重点)
1、所有数据都保存在叶子节点中:非叶子节点仅用于索引,不保存数据记录,这样可以提高查询性能,因为查找任何数据都必须从根节点遍历到叶子节点。
2、叶子节点之间通过链表连接:所有叶子节点按关键字的大小顺序链接,形成一个有序链表,这有利于范围查询和顺序访问。
3、更高的分支度:相较于B树,B+树每个节点可以存储更多的关键字,减少了树的高度,从而减少了磁盘I/O次数,提高了查询效率。
4、顺序访问性:由于叶子节点通过链表连接,B+树支持顺序遍历,这对于需要顺序访问数据的场景非常有用。
5、适应磁盘读写:B+树的节点大小通常与磁盘页的大小相同,这使得B+树能够很好地适应磁盘读写操作,减少磁盘I/O开销。
B+Tree在线演示地址:https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
B+tree 存放数据的查询效率问题
高度为2 时: 如果主键是bigint 1171 *16 = 18736 条数据 如果不 int 就是4个字节还可以翻倍
高度为3 时: 1171 * 1171 *16 = 21939856 大概2千多万条数据。所以通过主键查询效率很高。
Hash 索引:
hash索引就是采用hash算法,将key value 存储到hash 表中,如果有hash冲突就,用链表的方式解决。
有点单个数据查询速度快,但是不支持范围查询,不支持排序操作。 同理于 hashMap 和 redis
索引的分类:
分类 | 含义 | 特点 | 关键字 |
---|---|---|---|
主键索引 | 针对主键的索引 | 使用PRIMARY 默认自动创建,只能又一个 | PRIMARY |
唯一索引 | 避免重复数据,当你使用UNIQUE字段就会创建该索引 | 多个 | UNIQUE |
常规索引 | 快速定位特定数据 | 多个 | |
全文索引 | 全文检索关键字 | 多个 | FULLTEXT |
Mysql 的InnoDB引擎中,根据存储形式,又分为如下两种
名称 | 含义 |
---|---|
聚集索引 | 聚集索引的叶子节点直接包含了数据行本身,这意味着通过聚集索引可以直接访问到数据,无需再进行额外的查找 |
辅助索引 或 二级索引 | 辅助索引的叶子节点包含索引键值和一个指向数据行的指针(在InnoDB存储引擎中,辅助索引的叶子节点包含的是主键值,通过主键值再访问实际的数据行)。 |
当使用辅助索引查询数据时就涉及到了回表查询:
select * from user where id = 11;
select * from user where name = ‘zhangsan’
第一个查询,使用的主键查询,数据直接定位到数据。取出数据。
第二个查询,使用的是辅助索引,在查询到数据后,会得到数据的id,再通过id去主键索引去查询数据再取出数据(回表)。
实践题
users 表结构如下
id | name | phone | age | profession | create_time | |
---|---|---|---|---|---|---|
1 | 张三 | 1123123123 | xxx@qq.com | 20 | 软件 | 2022-12-12:00:00:00 |
2 | 李四 | 223123123 | xbx@qq.com | 21 | 土木 | 2022-12-12:00:00:00 |
- name字段为姓名字段,该字段的值可能会重复,为该字段创建索引。
- 删除name字段索引
- phone手机号字段的值,是非空,且唯一的,为该字段创建唯一索引。
- 为profdssion、age、email创建联合索引。
--查看索引
show index from users
--1. name字段为姓名字段,该字段的值可能会重复,为该字段创建索引。(未指定索引默认是Btree 也就是 B+tree)
create index idx_user_name on users;
--2、删除name字段索引
drop index idx_user_name ON users;
--3. phone手机号字段的值,是非空,且唯一的,为该字段创建唯一索引。
create unique index idx_user_phone on users(phone);
--4. 为profession、age、email 创建联合索引。
create index idx_user_pro_age_email on users(profession,age,email);
SQL 性能分析:
查看当前数据库的 增删改查的使用情况
show global status like 'Com_______';
慢查询日志:
-- 查看状态
show variables like 'slow_query_log'
目前是开启状态。如何开启,编辑my.cnf 文件 添加下面的语句,编辑完成后重启Mysql服务
vim /etc/my.cnf #编辑my.cnf文件
#新增下面3句
slow_query_log=1 # 开启慢sql
slow-query-log-file=/www/mysql-slow.log #存放日志的地方
long_query_time=3 # 表示超过3秒就记录下来。
#重启Mysql服务:
systemctl restart mysqld
之后如果定时查看 /www/mysql-slow.log 日志,就可以看是否有查过3秒的慢sql
下是一个例子。
查看sql 耗时情况
select @@have_profiling; -- 查看数据库支付支持
select @@profiling; -- 查看是否开启
set profiling = 1; -- 开启profiling
select * from a_img where id = 10
select * from a_img where img_url like '%24SN%'
show profiles;
通过 profiles就可以查看到最近 sql的执行时间
show profile cpu for query 126; #查询执行过程耗时:
执行过程 Explain
explain select * from student s, course c , student_coure sc where s.id = sc.studentid and c.id = sc.courseid;
EXPLAIN执行计划各字段含义:
【ld】 id相同,执行顺序从上到下; id不同,值越大,越先执行)。
【select_type】表示SELECT的类型,常见的取值有SIMPLE〈简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY (SELECT/WHERE之后包含了子查询)等
【key_len】 用到的索引长度,越短越好。
重点关注:【type】【possible_key】【key】
【type】表示连接类型,性能由好到差的连接类型为null > system > const > eq_ref > ref > range > index > all。
type = null 和 system: 一般不查询业务表,比如 select ‘A’
type = const: 主键或者unquie时,比如,select * from user where id= 1 或者 where idCard = 3423…
type = eq_ref 和 ref: 字段创建了索引 select * from user where name= ‘张三’ name 前提是建立了所以。
type = range ,常见于<、<=、>、>=、between等操作符(explain select * from user where age> 10 and user < 20),前提 age 字段必须是 unique 或者时主键 对数据建立了数据结构,否则依然能是 ALL 全文扫描。
type = index: 创建了索引,但是也是全字段扫描,说明索引效果不佳。
type = all: 没有创建索引的字段查询都是ALL explain select * from user where name= ‘zhangsan’
【possible_key】 可能用的的索引,如果是null 说明没用索引
【key】实际用到的索引