Mysql服务器内部架构(了解)
连接层
负责客户端的链接,验证账号密码等授权认证
服务层
对sql进行解析,优化,调用函数,如果是查询操作,有没有缓存等操作。
引擎层
是真正负责数据存储和提取的地方,mysql中提供多种引擎进行数据处理,可以根据需要进行数据选择
物理文件存储层
物理存储表数据,以及各种日志文件的地方
Mysql引擎
mysql中的引擎就是实际对数据操作的一种实施者,
不同的引擎的所使用的技术不同.
引擎种类:
SHOW ENGINES;
主要讲innodb和myisam
innodb引擎特点
是一个综合能力比较强的引擎,支持事务,行级锁,外键约束,全文索引,支持数据缓存等功能.
支持主键自增,不存储表的总行数(统计表的总行数,innodb中默认不存储,需要自己查询).
myisam
不支持事务,只支持表锁,增删改操作时会锁定整个表效率低,适合查询较多的情况
支持全文索引,存储表的总行数.
MySQL索引
什么是索引
数据库索引是为了实现高效数据查询的一种排好序的数据结构.
索引类似于书的目录,通过目录可以快速的定位到想要找到的数据.
因为一张表中的数据会有很多,如果直接去表中检索数据会效率低(逐行查找),
所以需要为表中的数据建立索引(一般主键默认会创建索引),这样就会提高查询效率
索引优势
提高了数据检索的效率,降低了数据库的IO成本;
通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗(索引是有序的);
索引劣势
1、占用磁盘空间;索引保存是要占用空间的.
2、增删改数据时,数据发生变化,索引也需要随之变动,也是需要开销的.
索引创建原则
哪些场景适合
主键 自动创建索引
查询条件列
多使用组合索引(多个列用一个索引)
,减少单值索引
建议排序和分组使用到的列
对数据量大的表
哪些场景不适合
表中数据比较少(类型表,菜单表,友情链接,系统信息表)
查询条件中用不到的列
增删改频率高的表
重复率高的列(性别 男 女)
索引分类
主键索引
创建表时,设置那个列为primary key 就是主键列,主键列就会自动创建索引
唯一索引
设置某个列数据唯一性,会创建唯一索引
单值索引
一个索引中,只包含一个列
组合索引(复合索引)
一个索引中包含多个列,节省了索引开支
在使用组合索引时,需要注意一个问题:满足组合索引最左前缀原则
在使用组合索引时,条件中必须要用到最左侧的列,否则索引失效
例如 a,b,c 3个列 a和b创建组合索引
使用时 where a=1 andb=2 索引生效
where a=1 and c=2 索引生效
where b=1 and c = 2 索引不生效
前缀索引
有些列长度比较大,需要只给前面指定的长度区间添加索引即可
全文索引
模糊查询时, 即使列有索引,也会导致索引失效
可以为列添加全文索引
CREATE FULLTEXT INDEX index_test2_title ON test2(title) WITH PARSER ngram; explain SELECT * FROM test2 WHERE MATCH(title) AGAINST('美国')
mysql索引数据结构
由于二叉树,平衡二叉树一个节点只能存储一个元素,再加上mysql使用自增主键,导致不适合二叉树,平衡二叉树.
mysql底层使用的是B+树,
一个节点中可以存储多个索引数据,
表数据都存储在叶子节点, 非叶子节点不存储表数据,只存索引, 这样一个节点就可以存储更多的索引,
叶子节点之间还有指针指向, 所以非常适合范围查询
聚簇索引和非聚族索引 区分方式: 找到了索引就找了你要找的数据 这种设计称为聚簇索引.
聚簇索引: innodb引擎中主键索引 就是聚簇索引,主键和数据在一个树上
非聚簇索引: myisam引擎中,由于索引和数据分别在两个不同的文件中存储,找到了索引,还需要重新查找一次,才能我到数据,这种称为非聚簇索引
innodb引擎中 像普通的索引也称为二级索引,他们也是非聚簇索引.
例如姓名,通过名字查找人的所有信息时,在姓名索引树种找到后,还需要在主键索引树种再次进行查找,最终在主键索引树中找到数据,这种称为非聚簇索引
回表查询
回表查询指的是查询时的次数
例如 学生有id,学号,姓名三个信息
select * from student where id=1 通过id(主键)查询学生所有的信息,这时只需要查询一次即可,
select * from student where 学号=12 通过学号查询学生所有信息,由于学号是普通索引,先通过学号,在学号索引树上找学号,然后再通过id去回表二次查询主键索引树,查询两次,称为回表查询
select 学号 from student where 学号=12 通过学号查询自己(判断学号是否存在),由于使用学号只查询学号本身,并不查询其他数据,这种情况下,我们可以在学号索引树上直接找到学号数据,这种情况就不需要回表查询了,这种情况也可以称为是聚簇索引
索引下推
将条件筛选过程下推到索引树上,
以前没有索引下推,先找具体的数据,然后再对数据进行条件过滤,查询的数据范围就比较大
使用索引下推,直接在索引树上进行条件筛选,筛选出符合条件的记录,然后只将符合条件的记录进行回表查询,减少了回表查询的次数。
适用于非主键索引
事务
什么是数据库事务?
首先数据库事务是数据库对执行操作的一种管理机制。
保证在同一个事务中,一次执行的多条sql,是一个不可分割的单元,多条sql要么都执行,要么都不执行。
数据库事务特征
原子性:一次执行的多条sql,是一个不可分割的单元,多条sql要么都执行,要么都不执行。这是事务最基本的特征。
持久性:保证事务提交时,数据在数据库是持久保存的,即使操作时,出现宕机。
隔离性:mysql是运行多个并发事务同时对数据进行读和写操作的,这是可以采用不同的隔离级别进行控制。
隔离级别:读 未提交,读 已提交 , 可重复读,串行化 一次只允许一个事务操作
一致性:数据库事务终极目标,在我们对数据库多次操作的过程中,最终要保证数据和我们预期的结果是一致的。
转账案例:多次对同一个账号的金额进行操作,最终结果是不能出现错误的。
事务隔离性,隔离级别
提供4种隔离级别
读 未提交: 一个事务可以读到另一个事务还未提交的数据. 并发最高的,也是最不安全的
问题: 会出现脏读,不可重复读,幻读问题
脏读: A事物修改了数据,还没提交,这时被B事务读到了,但是A事务有可能出错回滚了,
这种情况下,B事务读到的数据就是垃圾数据.
读 已提交: 一个事务只能读到另一个事务已提交的数据.
读 已提交 能够解决脏读问题,但是没有解决不可重复读和幻读问题
不可重复读问题: 在同一个事务中,读取同一个id的数据两次,两次读到的数据不一致.
可 重复读: 同一个事物读取多次相同数据,多次读取返回的结果是一致的.
可 重复读 解决了 不可重复读问题
普通的查询解决了 幻读问题, 如果在查询语句后面添加了 for update,就会出现幻读问题.
幻读问题: 同一个事务中,多次读取数据,读到行数不同
mysql中默认隔离级别是 可 重复读.
串行化: 相当于加锁了, 解决以上所有的问题, 当一个事务操作时,其他事务必须等待,即使执行的是查询操作.
事务实现原理
持久性实现: 使用到redo log日志文件(重做日志) 保证已提交事务的数据持久保持.
当事务提交后,先用redo log日志文件进行存储, 因为在此过程中,有可能宕机,
如果此时宕机,确保操作数据存储记录下来(日志文件中), 这样在服务恢复时,可以继续将日志文件中的数据,写入到物理硬盘上.
原子性实现: 使用到undo log 日志文件, 当我们执行一个insert语句时, 在undo log 日志文件中记录一个delete语句, 执行delete语句, 在日志文件中记录insert语句,记录一个操作的反向操作,
当事务回滚时,执行undo log 日志中的反向操作.
隔离性实现:
提到了MVCC机制(多版本并发控制), 每次事务对数据操作时,都都会记录一个历史记录(记录事务id,还会记录上一次操作事务id)
还提到了一个readView(读视图),
当隔离级别为 读 已提交时: 在一个事物中,每次读时,都会从历史版本记录中,获取一个最新的快照,
这样,就会导致每次读到的是最新的数据, 也就会出现不可重复读问题,
当隔离级别为 可 重复读时, 在第一次读时,会获取一个快照,之后再次读取时,还是从第一次生成的快照中读数据,所以,两次读到数据是一样的, 解决了不可重复读.
一致性实现: 以上是三个都满足,既可实现一致性
锁
mysql中读写不互斥(前提是没有使用串行化隔离级别)
但是写写操作是要互斥才行, mysql中使用锁机制来实现写写互斥.
按照锁的粒度分为:
全局锁: 锁定整个数据库,只允许读操作
一般在备份数据库时使用
FLUSH TABLES WITH READ LOCK
UNLOCK TABLES;
备份数据库语句 mysqldump --single-transaction -uroot -proot 库名> E:/文件名.sql
表级锁: 给整个表加锁
myisam引擎只支持表锁
innodb默认支持行锁,
行级锁: 加锁的粒度以行为单位
行级锁又可以分为:
行锁: 只锁定操作的那一行数据 使用的主键作为条件
间隙锁: 锁定的是一个范围 id>2 and id <6
临键锁: 是行锁和间隙锁的组合
共享锁:
主要是为查询语句添加的, 为查询语句如果添加了共享锁,那么其他事务可以读, 但是其他事务不能写的(指定的是同一条记录)
select * from employees where id = 1 lock in share mode为查询语句添加共享锁
读锁, 允许多个事务读, 不允许读写同时进行
排他锁: 就是互斥锁 当一个事物操作时,其他事务就不能进行加共享锁和排他锁操作.
insert ,update,delete操作时,自动会添加排他锁
查询操作如果需要添加排他锁, 可以在查询语句后面添加 for update语句
select * from employees where id = 1 for update
写锁