1.mysql和redis的数据库类型
mysql是关系型数据库,主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。
redis是NOSQL,即非关系型数据库,也是缓存数据库,即将数据存储在缓存中,缓存的读取速度快,能够大大的提高运行效率,但是保存时间有限
2.mysql的运行机制
mysql作为持久化存储的关系型数据库,相对薄弱的地方在于每次请求访问数据库时,都存在着I/O操作,如果反复频繁的访问数据库。第一:会在反复链接数据库上花费大量时间,从而导致运行效率过慢;第二:反复的访问数据库也会导致数据库的负载过高,那么此时缓存的概念就衍生了出来。
3.缓存
缓存就是数据交换的缓冲区(cache),当浏览器执行请求时,首先会对在缓存中进行查找,如果存在,就获取;否则就访问数据库。
缓存的好处就是读取速度快
4.redis数据库
redis数据库就是一款缓存数据库,用于存储使用频繁的数据,这样减少访问数据库的次数,提高运行效率。
https://www.cnblogs.com/Zhao159461/p/11131832.html
普通锁:(本质是串行执行)
一个事务开始操作以后,不允许其他事务读写
读写锁:(读读并发)
加读锁以后,只允许其他事物读。加写锁以后,阻塞其他读写的事务
MVCC(读写并发)
对于redo log,binlog这种日志进行的磁盘顺序读写
对于表空间磁盘文件里的数据页进行的磁盘随机读写
不是, 索引或者数据从从内存被剔除出去,肯定是遵循一定的算法的,以保障热点数据在内存中。不在内存中,那么就去硬盘去取好了,操作系统的虚拟内存机制简化了这种行为
在MySQL中索引是在存储引擎层实现的,而不是在服务器层实现的。不同存储引擎实现索引的方式也各有不同。
非主键索引的叶子节点存放的是主键的值,而主键索引的叶子节点存放的是整行数据,其中非主键索引也被称为二级索引,而主键索引也被称为聚簇索引。
DML(data manipulation language)数据操纵语言
就是我们最经常用到的 SELECT、UPDATE、INSERT、DELETE。 主要用来对数据库的表数据进行一些操作。
比如:
SELECT 列名称 FROM 表名称
UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....)
DELETE FROM 表名称 WHERE 列名称 = 值
当执行DML命令如果没有提交,将不会被其他会话看到。
除非在DML命令之后执行了DDL命令命令,或用户退出会话,或终止实例,此时系统会自动发出commit命令,使未提交的DML命令提交。
DDL(data definition language)数据定义语言
数据定义语言,用于定义和管理 SQL 数据库中的所有对象的语言
create table 创建表
alter table 修改表
drop table 删除表
truncate table 删除表中所有行
create index 创建索引
drop index 删除索引
当执行DDL语句时,在每一条语句前后,oracle都将提交当前的事务。
如果用户使用insert命令将记录插入到数据库后,执行了一条DDL语句(如create table),此时来自insert命令的数据将被提交到数据库。
当DDL语句执行完成时,DDL语句会被自动提交,不能回滚。
存储过程就是为以后的使用而保存的一条或多条MySQL语句的集合
优点:
分类:
查询:连接器(权限校验)、查询缓存(MySQL 8.0之后没有)、分析器(词法分析、语法分析)、优化器、执行器(权限校验、调用引擎接口)
更新(增删改):分析器(词法分析、语法分析)、权限校验、执行器、引擎层redo log预提交、写bin log、redo log提交
redo log是 InnoDB 的机制,不是MySQL的机制,所以只能被InnoDB 独享的。bin log是MySQL的机制,所以说可以被所有存储引擎共享。
并不是是说只用bin log就不行,只是InnoDB就是通过redo log来支持事务的持久化的。同时用bin log和redo log的话,必须要引入redo log的预提交,如果不用,就会出现以下情况:
先写 redo log 后写 bin log
假设在 redo log 写完,bin log 还没有写完的时候,MySQL 进程异常重启。redo log 写完之后,系统即使崩溃,仍然能够把数据恢复回来,
所以恢复后这一行 c 的值是 1。但是由于 bin log 没写完就 crash 了,这时候 bin log 里面就没有记录这个语句。因此,之后备份日志的时候,存起来的 bin log 里面就没有这条语句。如果需要用这个 bin log 来恢复临时库的话,由于这个语句的 bin log 丢失,这个临时库就会少了这一次更新,恢复出来的这一行 c 的值就是 0,与原库的值不同。
先写 bin log 后写 redo log
如果在 bin log 写完之后 crash,由于 redo log 还没写,崩溃恢复以后这个事务无效,所以这一行 c 的值是 0。但是 bin log 里面已经记录了 “把 c 从 0 改成 1” 这个日志。所以,在之后用 bin log 来恢复的时候就多了一个事务出来,恢复出来的这一行 c 的值就是 1,与原库的值不同。
主从一致性也会受到影响,因为slave根据master的bin log来保证数据的一致性。如果先写 bin log,在写入 bin log 那一刻,就有可能同步到备节点并执行,后续崩溃恢复删除这个 bin log 后,虽然保证了本节点的两个日志一致,但是这个被删除的 bin log 已经被备节点执行了
正常的事务提交过程:redo log预提交(prepare)-- 写bin log – redo log提交(commit)
binlog有记录,redolog状态commit:正常完成的事务,不需要恢复
binlog有记录,redolog状态prepare:在binlog写完提交事务之前的crash,恢复操作:提交事务
binlog无记录,redolog状态prepare:在binlog写完之前的crash,恢复操作:回滚事务
binlog无记录,redolog无记录:在redolog写之前crash,恢复操作:回滚事务
https://blog.csdn.net/weixin_29261711/article/details/113911911
重做日志(redo log)
作用:确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,重启 mysql 服务的时候,会根据 redo log进行重做,从而达到事务的持久性这一特性。
内容:物理格式的日志,记录的是物理数据页面的修改信息,其 redo log 是顺序写入 redo log file 的物理文件中去的。
产生时间:事务开始后就产生了 redo log。在事务执行的过程中,便开始写入 redo log 文件中。
释放:当对应事务的脏页写入到磁盘之后,redo log 的使命也就完成了。
回滚日志(undo log)
作用:保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC)。
内容:逻辑格式的日志,在执行 undo 的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现。
产生时间:事务开始之前,将当前版本生成 undo log,undo 也会产生 redo 来保证 undo 的可靠性。
释放:当事务提交后,undo log 并不能立马被删除,而是放入待清理的链表。
二进制日志(bin log)
作用:用于主从复制,从库利用主库上的 binlog 进行relay,实现主从同步。还可以用于数据库基于时间点的还原。
内容:逻辑格式的日志,可以简单认为就是执行过的事务中的 sql 语句。但又不完全是 sql 语句那么简单,而是包括了执行 sql 语句反向的信息,比如 delete 对应着其反向的 insert 等。
产生时间:事务提交的时候,一次性将事务中的 sql 语句按照一定格式记录到 binlog。在开启了 binlog 的情况下,对于大事务的提交,可能会变得比较慢一些,这是因为 binlog 会在事务提交的时候一次性写入造成的。
补充
二进制日志的作用之一是还原数据库的,与 redo log 很类似。
作用不同:redo log 是保证事务持久性的,是事务层面的,binlog 作为还原的功能,是数据库层面的,虽然都有还原的意思,但是其保护的数据的层次是不一样的。
内容不同:redo log 是物理日志,是数据页面修改之后的物理记录,binlog 是逻辑日志,可以简单理解为就是 sql 语句。
恢复数据时的效率,基于物理日志的 redo log 恢复数据的效率要高于逻辑日志的 binlog。
MySql 时通过两阶段提交来保证事务一致性的,也就是 redo log 和 binlog 的一致性,理论上是先写 redo log,再写 binlog,两个日志都写入成功(刷入磁盘),事务才算真正的完成。
聚簇索引叶子节点保存行记录,辅助索引是一种非聚簇索引,叶子结点保存主键。使用辅助索引查询行记录需要先找到主键,用这个主键再去聚簇索引中再查一遍,这个过程就叫回表查询
跳跃表基于有序单链表,在链表的基础上,每个结点不只包含一个指针,还可能包含多个指向后继结点的指针,这样就可以跳过一些不必要的结点,从而加快查找、删除等操作。
查找的时间复杂度:平均O(logN)、最坏O(N)
传统的单链表是一个线性结构,向有序的链表中插入、查找一个结点需要O(n)的时间。如果使用上图的跳跃表,就可以减少查找所需的时间。
跳跃表的插入和删除操作都基于查找操作,理解了查找操作,也就理解了跳跃表的本质。查找就是给定一个key,查找这个key是否出现在跳跃表中。
跳表的使用场景:
Redis使用跳跃表作为有序集合键的底层实现之一,若一个有序集合包含的元素数量比较多,或者有序集合中的成员是比较长的字符串时,Redis就会使用跳跃表来作为有序集合键的底层实现。
有序集合使用两种数据结构来实现,从而可以使插入和删除操作达到O(log(N))的时间复杂度。这两种数据结构是哈希表和跳跃表。向哈希表添加元素,用于将成员对象映射到分数;同时将该元素添加到跳跃表,以分数进行排序。
MySQL的默认隔离级别就是Repeatable read(可重复读)
Serializable(序列化)是最高的事务隔离级别,同时代价也花费最高,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读。
优点:
缺点:
RDB文件是一个压缩后的二进制文件,通过该文件可以还原生成RDB文件时的数据库状态
生成RDB文件的方式:
RDB文件能够实现重启服务器的时候使用,还能够实现主从复制(将RDB文件传输至slave)
间隙锁是一个在索引记录之间的间隙上的锁。这是mysql数据库中的一种锁,它会出现在如下场景中,我们向表中新增一条数据age=20,这条数据在本来是没有的,在insert还没有提交的时候去
select * from tableA a where a.age>15 and a.age<25
这个时候就会触发间隙锁,我们必须等待insert提交后才能执行select语句。
在MySQL的InnoDB引擎中,如果操作的是一个区间的数据,会锁住这个区间所有的记录,即使这个记录不存在,这个时候另一个会话去插入这个区间的数据,就必须等待上一个结束。
间隙锁的作用:保证某个间隙内的数据在锁定情况下不会发生任何变化。比如mysql默认隔离级别下的可重复读(RR)。
ps: 可重复读(RR):在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。
内联接(Inner Join):匹配2张表中字段相等的记录。
左联接(Left Outer Join):返回左表,并且返回左表与右表字段相等的记录
右联接(Right Outer Join):返回右表,并且返回右表与左表字段相等的记录
https://www.cnblogs.com/hongmoshui/p/10429842.html
联合索引又叫复合索引。两个或更多个列上的索引被称作复合索引
对于复合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。例如索引是key index (a,b,c)。 可以支持***a | a,b| a,b,c*** 3种组合进行查找,但不支持 b,c进行查找
这是因为:多列索引是先按照第一列进行排序,然后在第一列排好序的基础上再对第二列排序,如果没有第一列的话,直接访问第二列,那第二列肯定是无序的,直接访问后面的列就用不到索引了
例如组合索引(a,b,c),组合索引的生效原则是 :从前往后依次使用生效,如果中间某个索引没有使用,那么断点前面的索引部分起作用,断点后面的索引没有起作用
where a=3 and b=4 and c=5 … 这种三个索引顺序使用中间没有断点,全部发挥作用;
where a=3 and c=5… 这种情况下b就是断点,a发挥了效果,c没有效果
where b=3 and c=4… 这种情况下a就是断点,在a后面的索引都没有发挥作用,这种写法联合索引没有发挥任何效果;
where b=4 and a=3 and c=5 … 这个跟第一个一样,全部发挥作用,abc只要用上了就行,跟写的顺序无关
组合索引使用判断:
(0) select * from mytable where a=3 and b=5 and c=4;
abc三个索引都在where条件里面用到了,而且都发挥了作用
(1) select * from mytable where c=4 and b=6 and a=3;
这条语句列出来只想说明 mysql没有那么笨,where里面的条件顺序在查询之前会被mysql自动优化,效果跟上一句一样
(2) select * from mytable where a=3 and c=7;
a用到索引,b没有用,所以c是没有用到索引效果的
(3) select * from mytable where a=3 and b>7 and c=3;(范围值就算是断点)
a用到了,b也用到了,c没有用到,这个地方b是范围值,也算断点,只不过自身用到了索引
(4) select * from mytable where b=3 and c=4;
因为a索引没有使用,所以这里 bc都没有用上索引效果
(5) select * from mytable where a>4 and b=7 and c=9;
a用到了 b没有使用,c没有使用
(6) select * from mytable where a=3 order by b;
a用到了索引,b在结果排序中也用到了索引的效果,前面说了,a下面任意一段的b是排好序的
(7) select * from mytable where a=3 order by c;
a用到了索引,但是这个地方c没有发挥排序效果,因为中间断点了,使用 explain 可以看到 filesort
(8) select * from mytable where b=3 order by a;
b没有用到索引,排序中a也没有发挥索引效果
https://www.cnblogs.com/shizhengwen/p/9283973.html
https://blog.csdn.net/a1158375969/article/details/105898424
当发生数据库宕机时,可能 InnoDB存储引擎正在写入某个页到表中,而这个页只写了一部分,比如16KB的页,只写了前4KB,之后就发生了宕机,这种情况被称为部分写失效(partial page write)。
在 InnoDB存储引擎未使用 doublewrite技术前,曾经出现过因为部分写失效而导致数据丢失的情况。
有经验的DBA也许会想,如果发生写失效,可以通过重做日志进行恢复。这是个办法。但是必须清楚地认识到,重做日志中记录的是对页的物理操作。如果这个页本身已经发生了损坏,再对其进行重做是没有意义的。这就是说,在应用重做日志前,用户需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是 doublewrite。
Double Write的思路很简单:
A. 在覆盖磁盘上的数据前,先将Page的内容写入到磁盘上的其他地方(InnoDB存储引擎中的doublewrite buffer,这里的buffer不是内存空间,是持久存储上的空间).
B. 然后再将Page的内容覆盖到磁盘上原来的数据。
如果在A步骤时系统故障,原来的数据没有被覆盖,还是完整的。
如果在B步骤时系统故障,原来的数据不完整了,但是新数据已经被完整的写入了doublewrite buffer. 因此系统恢复时就可以用doublewrite buffer中的新Page来覆盖这个不完整的page。
高频访问优化:分表分库、增加缓存、增加索引
并发优化:主从读写分离、集群与分布式减轻负载