数据库

| 行锁(Record Lock):锁直接加在索引记录上面,锁住的是key。

l 间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙不变。间隙锁是针对事务隔离级别为可重复读或以上级别而已的。

l Next-Key Lock :行锁和间隙锁组合起来就叫Next-Key Lock。

MyISAM 和 InnoDB

InnoDB存储引擎
InnoDB是事务型数据库的首选引擎,支持事务安全表
(ACID),支持行锁定和外键,InnoDB是默认的Mysql
引擎。主要特性有:
1、InnoDB给MySQL提供了具有提交、回滚和崩溃回复
能力的事务安全(ACID兼容)存储引擎。InnoDB锁定
在行级并且也在select语句中提供了一个类似Oracle
的非锁定读。这些功能增加了用户部署和性能。在SQL
查询中,可以自由地将InnoDB类型的表和其他MySQL的
表类型混合起来,甚至在同一个查询中也可以混合。
2、InnoDB是为处理巨大数据量的最大性能设计的。
它的CPU效率可能是任何其他基于磁盘的关系型数据
库引擎锁不能匹敌的。
3、InnoDB存储引擎完全与MySQL服务器整合,InnoDB存
储引擎为在主内存中缓存数据和索引而维持它自己的缓
冲池。InnoDB将它的表和索引在一个逻辑表空间中,表
空间可以包含数个文件(或原始磁盘文件)。这与MyISAM
表不同,比如在M有ISAM表中每个表被存放在分离的文件中。
InnoDB表可以是任何尺寸。
4、InnoDB支持外键完整性约束,存储表中的数据时,每
张表的存储都按主键顺序存放,如果没有显示在表定义时
指定主键,InnoDB会为每一行生成一个6字节的ROWID,并以
此为主键
5、InnoDB被用在众多需要高性能的大型数据库站点上。
InnoDB不创建目录,使用InnoDB时,MySQL将在MySQL
数据目录下创建一个名为ibdata1的10M大小的自动扩
展数据文件,以及两个名为ib_longfile0和ib_logfile
1的5MB大小的日志文件。
#### MyISAM存储引擎
MyISAM基于ISAM存储引擎,并对其进行扩展。它在web、
数据仓储和其他应用环境下最常使用的存储引擎之一。
拥有较高的插入、查询速度,但不支持事务。
#### MEMORY存储引擎
MEMORY存储引擎将表中的数据存储在内存中未查询和
引用其他表数据提供快速访问。

使用场景:
1、如果需要提供提交、回滚、奔溃恢复能力的事务安全
(ACID兼容)能力,并要求实现并发控制,InnoDB是一个
好的选择
2、如果数据表主要用来插入和查询记录,则MyISAM引擎能
提供较高的处理效率。
3、如果只是临时存放数据,数据量不大,并且不需要较
高的数据安全性,可以选择将数据保存在内存中的Memory
引擎,MySQL中使用该引擎作为临时表,存放查询的中间结
果。
4、如果只有insert和select操作,可以选择Archive,
Archive支持高并发的插入操作,但是本身不是事务安全的。
Archive非常适合存储归档数据,如记录日志信息可以使用
Archive
灵活选择,一个数据库中多个表可以使用不同引擎以满足各种
性能和实际需求,使用合适的存储引擎,将会提高整个数据库
的性能

聚簇索引和非聚簇索引

这两种是按照存储结构划分的。

每个InnoDB表都有一个特殊的索引,称为聚簇索引,用于存储行数据。

聚簇索引(也称为主键索引)就是携带了行数据的索引,非聚簇索引就是除了聚簇索引之外的索引。

可以看到聚簇索引后面是直接跟着的数据,而非聚簇索引指向的是聚簇索引的key值。

因此非聚簇索引查询数据需要先查到聚簇索引的key,然后用这个key去查询真正的数据(这个过程称为回表)。

也就是说非聚簇索引是需要查询两次

复合索引

MySQL复合索引,是创建在多个列上的索引,所以也叫多列索引。MySQL允许创建一个最多由16列组成的复合索引。如果在索引定义中以正确的顺序指定列,则单个复合索引可以加快对同一表的这类查询的速度。

两个或更多个列上的索引被称作复合索引。
利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引不同于使用两个单独的索引。复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。如果您知道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不姓,电话簿将没有用处。

所以说创建复合索引时,应该仔细考虑列的顺序。对索引中的所有列执行搜索或仅对前几列执行搜索时,复合索引非常有用;仅对后面的任意列执行搜索时,复合索引则没有用处。

MySQL InnoDB下的当前读和快照读

  • 当前读:像select lock in share mode(共享锁)、select for update、insert、delete(排他锁)这些操作是一种当前读,就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取记录进行加锁(当前读可以被认为是悲观锁的具体功能实现)
  • 快照读:不加锁的select就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但在很多情况下,避免了加锁的操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而可能是之前的历史版本。快照读就是mvcc思想在mysql的具体非阻塞读功能实现,mvcc的目的就是为了实现读-写冲突不加锁,提高并发读写性能,而这个读指的就是快照读。快照读就是MySQL为我们实现mvcc理想模型的器重你一个具体非阻塞读功能

MVCC

MVCC 多版本控制实现读取数据不用加锁, 可以让读取数据同时修改。修改数据时同时可读取。

MVCC是在并发访问数据库时,通过对数据做多版本管理,避免因为写锁的阻塞而造成读数据的并发阻塞问题。

通俗的讲就是MVCC通过保存数据的历史版本,根据比较版本号来处理数据的是否显示,从而达到读取数据的时候不需要加锁就可以保证事务隔离性的效果

主要是由1、事务版本号;2、表的隐藏列;3、undo log 4、read view实现的

在innodb 中每个SQL语句执行前都会得到一个read_view。副本主要保存了当前数据库系统中正处于活跃(没有commit)的事务的ID号,其实简单的说这个副本中保存的是系统中当前不应该被本事务看到的其他事务id列表。

Innodb实现MVCC的原理:1、获得事务版本号;2、获得一个read view;3、查询到数据,与read view事务版本号进行匹配;4、不符合read view规则的从undo log里获得历史版本数据;5、返回符合规则的数据

MVCC不存在幻读问题的,但也并不是说MVCC解决了幻读的问题,经过理论的推断和验证得到的结论是在快照读的情况下可以避免幻读问题,在当前读的情况下则需要使用间隙锁来解决幻读问题的。

TiDB数据是怎么组织的

TiDB 由三个组件组成,分别是 TiDB Server、TiKV Server 和 PD Server。

TiKV 将关系模型中的表格数据转换成 Key-Value 的形式存储在磁盘中,TiDB 则负责完成客户端 SQL 请求的解析和执行。这两个组件已经完成了数据的存储和读写查询,基本实现了一个单机的数据库系统。

TiDB 系统是在大数据场景下诞生的,它的设计初衷是处理分布式的数据库,并具有高可用性和无限的水平扩展能力。那么,这种分布式集群里事务的调度和数据的容灾是如何实现的?

这是由另一个组件 PD Server(后面以 PD 来简称这个组件)来完成的。PD 自身是一个集群, 由多个 Server 组成,有一套选举的策略,由一个 Leader 对外提供服务。

当 PD 崩溃时,系统会重新选举其他节点作为 Leader 来提供服务,无须担心 PD 节点的失效。

精度缺失

在需要精确的表示两位小数时我们需要把他们转换为BigDecimal对象,然后再进行运算。

另外需要注意

使用BigDecimal(double val)构造函数时仍会存在精度丢失问题,建议使用BigDecimal(String val)

这就需要先把double转换为字符串然后在作为BigDecimal(String val)构造函数的参数。转换为BigDecimal对象

之后再进行加减乘除操作,这样精度就不会出现问题了。这也是为什么有关金钱数据存储都使用BigDecimal。

mysql架构

MySQL大体上分为Server层和存储引擎层两部分;

Server层:

  • 连接器:TCP握手后服务器来验证登陆用户身份,A用户创建连接后,管理员对A用户权限修改了也不会影响到已经创建的链接权限,必须重新登陆。
  • 查询缓存:查询后的结果存储位置,MySQL8.0版本以后已经取消,因为查询缓存失效太频繁,得不偿失。
  • 分析器:根据语法规则,判断你输入的这个SQL语句是否满足MySQL语法。
  • 优化器:多种执行策略可实现目标,系统自动选择最优进行执行。
  • 执行器:判断是否有权限,将最终任务提交到存储引擎。

存储引擎层:

负责数据的存储和提取。其架构模式是插件式的,支持InnoDBMyISAMMemory等多个存储引擎。现在最常用的存储引擎是InnoDB,它从MySQL 5.5.5版本开始成为了默认存储引擎(经常用的也是这个)。

SQL执行顺序

MySQL调优

数据库管理员可以使用SHOW ATATUS语句查询MySQL数据库的性能

sql优化主要分四个方向:sql语句跟索引、表结构、系统配置、硬件

总优化思路就是最大利用索引、尽可能避免全表扫描。减少无效数据查询

1、减少数据访问:设置合理的字段类型,启用压缩,通过索引访问等减少磁盘 IO。

2、返回更少的数据:只返回需要的字段和数据分页处理,减少磁盘 IO 及网络 IO。

3、减少交互次数:批量 DML 操作,函数存储等减少数据连接次数。

4、减少服务器 CPU 开销:尽量减少数据库排序操作以及全表查询,减少 CPU 内存占用 。

5、分表分区:使用表分区,可以增加并行操作,更大限度利用 CPU 资源。

SQL语句优化大致举例

SQL语句优化大致举例

1、合理建立覆盖索引:可以有效减少回表。

2、union,or,in都能命中索引,建议使用in

3、负向条件(!=、<>、not in、not exists、not like 等) 索引不会使用索引,建议用in。

4、在列上进行运算或使用函数会使索引失效,从而进行全表扫描

5、小心隐式类型转换,原字符串用整型会触发CAST函数导致索引失效。原int用字符串则会走索引。

6、不建议使用%前缀模糊查询。

7、多表关联查询时,小表在前,大表在后。在 MySQL 中,执行 from 后的表关联查询是从左往右执行的(Oracle 相反),第一张表会涉及到全表扫描。

8、调整 Where 字句中的连接顺序,MySQL 采用从左往右,自上而下的顺序解析 where 子句。根据这个原理,应将过滤数据多的条件往前放,最快速度缩小结果集。

SQL调优大致思路

1、先用慢查询日志定位具体需要优化的sql

2、使用 explain 执行计划查看索引使用情况

3、重点关注(一般情况下根据这4列就能找到索引问题):

1、key(查看有没有使用索引)

2、key_len(查看索引使用是否充分)

3、type(查看索引类型)

4、Extra(查看附加信息:排序、临时表、where条件为false等)

4、根据上1步找出的索引问题优化sql 5、再回到第2步

表结构优化

1、尽量使用TINYINT、SMALLINT、MEDIUM_INT作为整数类型而非INT,如果非负则加上UNSIGNED 。

2、VARCHAR的长度只分配真正需要的空间 。

3、尽量使用TIMESTAMP而非DATETIME 。

4、单表不要有太多字段,建议在20以内。

5、避免使用NULL字段,很难查询优化且占用额外索引空间。字符串默认为’’。

读写分离

只在主服务器上写,只在从服务器上读。对应到数据库集群一般都是一主一从、一主多从。业务服务器把需要写的操作都写到主数据库中,读的操作都去从库查询。主库会同步数据到从库保证数据的一致性。一般 读写分离 的实现方式有两种:代码封装数据库中间件

分库分表分库分表分为垂直和水平两个方式,一般是先垂直后水平

1、垂直分库:将应用分为若干模块,比如订单模块、用户模块、商品模块、支付模块等等。其实就是微服务的理念。

2、垂直分表:一般将不常用字段跟数据较大的字段做拆分。

3、水平分表:根据场景选择什么字段作分表字段,比如淘宝日订单1000万,用userId作分表字段,数据查询支持到最近6个月的订单,超过6个月的做归档处理,那么6个月的数据量就是18亿,分1024张表,每个表存200W数据,hash(userId)%100找到对应表格。

4、ID生成器:分布式ID 需要跨库全局唯一方便查询存储-检索数据,确保唯一性跟数字递增性。

目前主要流行的分库分表工具 就是Mycatsharding-sphere

TiDB:开源分布式数据库,结合了传统的 RDBMS 和NoSQL 的最佳特性。TiDB 兼容 MySQL,支持无限的水平扩展,具备强一致性和高可用性。TiDB 的目标是为 OLTP(Online Transactional Processing) 和 OLAP (Online Analytical Processing) 场景提供一站式的解决方案。TiDB 具备如下核心特点

1、支持 MySQL 协议(开发接入成本低)。

2、100% 支持事务(数据一致性实现简单、可靠)。

3、无限水平拓展(不必考虑分库分表),不停服务。

4、TiDB 支持和 MySQL 的互备。

5、遵循jdbc原则,学习成本低,强关系型,强一致性,不用担心主从配置,不用考虑分库分表,还可以无缝动态扩展。

适合:

1、原业务的 MySQL 的业务遇到单机容量或者性能瓶颈时,可以考虑使用 TiDB 无缝替换 MySQL。

2、大数据量下,MySQL 复杂查询很慢。

3、大数据量下,数据增长很快,接近单机处理的极限,不想分库分表或者使用数据库中间件等对业务侵入性较大、对业务有约束的 Sharding 方案。

4、大数据量下,有高并发实时写入、实时查询、实时统计分析的需求。5、有分布式事务、多数据中心的数据 100% 强一致性、auto-failover 的高可用的需求。

不适合:

1、单机 MySQL 能满足的场景也用不到 TiDB。

2、数据条数少于 5000w 的场景下通常用不到 TiDB,TiDB 是为大规模的数据场景设计的。

3、如果你的应用数据量小(所有数据千万级别行以下),且没有高可用、强一致性或者多数据中心复制等要求,那么就不适合使用 TiDB。

查询 explain

查询的信息:

  • id:表示SELECT语句的编号
  • select_type:表示SELECT语句的类型。
  • table:表示查询的表
  • possible_key:表示查询中可能使用的索引
  • key:表示查询使用到的索引
  • key_len:表示索引字段的长度
  • ref:表示使用哪个列或常数与索引一起来查询记录
  • rows:表示查询的行数
  • Extra:表示查询过程的附件信息

Driver、url、user、password

日志

一、什么是binlog

binlog其实在日常的开发中是听得很多的,因为很多时候数据的更新就依赖着binlog

举个很简单的例子:我们的数据是保存在数据库里边的嘛,现在我们对某个商品的某个字段的内容改了(数据库变更),而用户检索的出来数据是走搜索引擎的。为了让用户能搜到最新的数据,我们需要把引擎的数据也改掉。

一句话:数据库的变更,搜索引擎的数据也需要变更

于是,我们就会监听binlog的变更,如果binlog有变更了,那我们就需要将变更写到对应的数据源。

什么是binlog

binlog记录了数据库表结构和表数据变更,比如update/delete/insert/truncate/create。它不会记录select(因为这没有对表没有进行变更)

binlog长什么样?

binlog我们可以简单理解为:存储着每条变更的SQL语句(当然从下面的图看来看,不止SQL,还有XID「事务Id」等等)

binlog一般用来做什么

主要有两个作用:复制和恢复数据

  • MySQL在公司使用的时候往往都是一主多从结构的,从服务器需要与主服务器的数据保持一致,这就是通过binlog来实现的
  • 数据库的数据被干掉了,我们可以通过binlog来对数据进行恢复。

因为binlog记录了数据库表的变更,所以我们可以用binlog进行复制(主从复制)和恢复数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xGHosIZz-1616910669984)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]

二、什么是redo log

假设我们有一条sql语句:

update user_table set name='java3y' where id = '3'

MySQL执行这条SQL语句,肯定是先把id=3的这条记录查出来,然后将name字段给改掉。这没问题吧?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gyk2q1zG-1616910669985)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]

实际上Mysql的基本存储结构是(记录都存在页里边),所以MySQL是先把这条记录所在的找到,然后把该页加载到内存中,将对应记录进行修改。

现在就可能存在一个问题:如果在内存中把数据改了,还没来得及落磁盘,而此时的数据库挂了怎么办?显然这次更改就丢了。

如果每个请求都需要将数据立马落磁盘之后,那速度会很慢,MySQL可能也顶不住。所以MySQL是怎么做的呢?

MySQL引入了redo log,内存写完了,然后会写一份redo log,这份redo log记载着这次在某个页上做了什么修改

其实写redo log的时候,也会有buffer,是先写buffer,再真正落到磁盘中的。至于从buffer什么时候落磁盘,会有配置供我们配置。

redo log也是需要写磁盘的,但它的好处就是顺序IO(我们都知道顺序IO比随机IO快非常多)。

所以,redo log的存在为了:当我们修改的时候,写完内存了,但数据还没真正写到磁盘的时候。此时我们的数据库挂了,我们可以根据redo log来对数据进行恢复。因为redo log是顺序IO,所以写入的速度很快,并且redo log记载的是物理变化(xxxx页做了xxx修改),文件的体积很小,恢复速度很快

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7x6ya0yq-1616910669988)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]

三、binlog和redo log

看到这里,你可能会想:binlogredo log 这俩也太像了吧,都是用作”恢复“的。

其实他俩除了"恢复"这块是相似的,很多都不一样,下面看我列一下。

存储的内容

binlog记载的是update/delete/insert这样的SQL语句,而redo log记载的是物理修改的内容(xxxx页修改了xxx)。

所以在搜索资料的时候会有这样的说法:redo log 记录的是数据的物理变化binlog记录的是数据的逻辑变化

功能

redo log的作用是为持久化而生的。写完内存,如果数据库挂了,那我们可以通过redo log来恢复内存还没来得及刷到磁盘的数据,将redo log加载到内存里边,那内存就能恢复到挂掉之前的数据了。

binlog的作用是复制和恢复而生的。

  • 主从服务器需要保持数据的一致性,通过binlog来同步数据。
  • 如果整个数据库的数据都被删除了,binlog存储着所有的数据变更情况,那么可以通过binlog来对数据进行恢复。

又看到这里,你会想:”如果整个数据库的数据都被删除了,那我可以用redo log的记录来恢复吗?“不能

因为功能的不同,redo log 存储的是物理数据的变更,如果我们内存的数据已经刷到了磁盘了,那redo log的数据就无效了。所以redo log不会存储着历史所有数据的变更,文件的内容会被覆盖的

binlog和redo log 写入的细节

redo log是MySQL的InnoDB引擎所产生的。

binlog无论MySQL用什么引擎,都会有的。

InnoDB是有事务的,事务的四大特性之一:持久性就是靠redo log来实现的(如果写入内存成功,但数据还没真正刷到磁盘,如果此时的数据库挂了,我们可以靠redo log来恢复内存的数据,这就实现了持久性)。

上面也提到,在修改的数据的时候,binlog会记载着变更的类容,redo log也会记载着变更的内容。(只不过一个存储的是物理变化,一个存储的是逻辑变化)。那他们的写入顺序是什么样的呢?

redo log事务开始的时候,就开始记录每次的变更信息,而binlog是在事务提交的时候才记录。

于是新有的问题又出现了:我写其中的某一个log,失败了,那会怎么办?现在我们的前提是先写redo log,再写binlog,我们来看看:

  • 如果写redo log失败了,那我们就认为这次事务有问题,回滚,不再写binlog
  • 如果写redo log成功了,写binlog,写binlog写一半了,但失败了怎么办?我们还是会对这次的事务回滚,将无效的binlog给删除(因为binlog会影响从库的数据,所以需要做删除操作)
  • 如果写redo logbinlog都成功了,那这次算是事务才会真正成功。

简单来说:MySQL需要保证redo logbinlog数据是一致的,如果不一致,那就乱套了。

  • 如果redo log写失败了,而binlog写成功了。那假设内存的数据还没来得及落磁盘,机器就挂掉了。那主从服务器的数据就不一致了。(从服务器通过binlog得到最新的数据,而主服务器由于redo log没有记载,没法恢复数据)
  • 如果redo log写成功了,而binlog写失败了。那从服务器就拿不到最新的数据了。

MySQL通过两阶段提交来保证redo logbinlog的数据是一致的。

过程:

  • 阶段1:InnoDBredo log 写盘,InnoDB 事务进入 prepare 状态
  • 阶段2:binlog 写盘,InooDB 事务进入 commit 状态
  • 每个事务binlog的末尾,会记录一个 XID event,标志着事务是否提交成功,也就是说,恢复过程中,binlog 最后一个 XID event 之后的内容都应该被 purge。

四、什么是undo log

undo log有什么用?

undo log主要有两个作用:回滚和多版本控制(MVCC)

在数据修改的时候,不仅记录了redo log,还记录undo log,如果因为某些原因导致事务失败或回滚了,可以用undo log进行回滚

undo log主要存储的也是逻辑日志,比如我们要insert一条数据了,那undo log会记录的一条对应的delete日志。我们要update一条记录时,它会记录一条对应相反的update记录。

这也应该容易理解,毕竟回滚嘛,跟需要修改的操作相反就好,这样就能达到回滚的目的。因为支持回滚操作,所以我们就能保证:“一个事务包含多个操作,这些操作要么全部执行,要么全都不执行”。【原子性】

因为undo log存储着修改之前的数据,相当于一个前版本,MVCC实现的是读写不阻塞,读的时候只要返回前一个版本的数据就行了。

数据库事务

事务(Transaction)是由一系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元。事务是DBMS中最基础的单位,事务不可分割。

事务具有4个基本特征,分别是:原子性(Atomicity)、一致性(Consistency)、隔离性

(Isolation)、持久性(Duration),简称ACID。

1)原子性(Atomicity)原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,[删删删]因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

2)一致性(Consistency)

一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

3)隔离性(Isolation)

隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

多个事务并发访问时,事务之间是隔离的,一个事务不应该影响其它事务运行效果。这指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。

不同的隔离级别:

Read Uncommitted(读取未提交[添加中文释义]内容):最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。

Read Committed(读取提交内容):只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。

Repeated Read(可重复读):在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。

Serialization(可串行化):事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。

4)持久性(Durability)

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

脏读、幻读、不可重复读

脏读:脏读是指一个事务在处理过程中读取了另一个还没提交的事务的数据。

比如A向B转账100,A的账户减少了100,而B的账户还没来得及修改,此时一个并发的事务访问到了B的账户,就是脏读

不可重复读:不可重复读是对于数据库中的某一个字段,一个事务多次查询却返回了不同的值,这是由于在查询的间隔中,该字段被另一个事务修改并提交了。

比如A第一次查询自己的账户有1000元,此时另一个事务给A的账户增加了1000元,所以A再次读取他的账户得到了2000的结果,跟第一次读取的不一样。

不可重复读与脏读的不同之处在于,脏读是读取了另一个事务没有提交的脏数据,不可重复读是读取了已经提交的数据,实际上并不是一个异常现象。

幻读:事务多次读取同一个范围的时候,查询结果的记录数不一样,这是由于在查询的间隔中,另一个事务新增或删除了数据。

比如A公司一共有100个人,第一次查询总人数得到100条记录,此时另一个事务新增了一个人,所以下一次查询得到101条记录。

不可重复度和幻读的不同之处在于,幻读是多次读取的结果行数不同,不可重复度是读取结的值不同。

避免不可重复读需要锁行,避免幻读则需要锁表。

脏读,不可重复读和幻读都是数据库的读一致性问题,是在并行的过程中出现的问题,必须采用一定的隔离级别解决。

索引设计准则:三星索引

上文我们得出了一个索引列顺序的经验 法则:将选择性最高的列放在索引的最前列,这种建立在某些场景可能有用,但通常不如避免随机 IO 和 排序那么重要,这里引入索引设计中非常著名的一个准则:三星索引。

如果一个查询满足三星索引中三颗星的所有索引条件,理论上可以认为我们设计的索引是最好的索引。什么是三星索引

  1. 第一颗星:WHERE 后面参与查询的列可以组成了单列索引或联合索引
  2. 第二颗星:避免排序,即如果 SQL 语句中出现 order by colulmn,那么取出的结果集就已经是按照 column 排序好的,不需要再生成临时表
  3. 第三颗星:SELECT 对应的列应该尽量是索引列,即尽量避免回表查询。

索引分类

MySQL索引类型:数据结构角度:B+tree索引
hash索引
fulltext索引
存储角度:聚簇索引
非聚簇索引
逻辑角度:主键索引
唯一索引
普通索引
联合索引
覆盖索引

主键索引:主键索引的叶子节点存的是整行数据信息。在InnoDB里,主键索引也被称为聚簇索引(clustered index)。主键自增是无法保证完全自增的哦,遇到唯一键冲突、事务回滚等都可能导致不连续。

唯一索引:以唯一列生成的索引,该列不允许有重复值,但允许有空值(NULL)

普通索引跟唯一索引查询性能:InnoDB的数据是按数据页为单位来读写的,默认每页16KB,因此这两种索引查询数据性能差别微乎其微。

change buffer:普通索引用在更新过程的加速,更新的字段如果在缓存中,如果是普通索引则直接更新即可。如果是唯一索引需要将所有数据读入内存来确保不违背唯一性,所以尽量用普通索引。

非主键索引:非主键索引的叶子节点内容是主键的值。在InnoDB里,非主键索引也被称为二级索引(secondary index)

回表:先通过数据库索引扫描出数据所在的行,再通过行主键id取出索引中未提供的数据,即基于非主键索引的查询需要多扫描一棵索引树。

覆盖索引:如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为覆盖索引。

联合索引:相对单列索引,组合索引是用多个列组合构建的索引,一次性最多联合16个。

最左前缀原则:对多个字段同时建立的组合索引(有顺序,ABC,ACB是完全不同的两种联合索引) 以联合索引(a,b,c)为例,建立这样的索引相当于建立了索引a、ab、abc三个索引。另外组合索引实际还是一个索引,并非真的创建了多个索引,只是产生的效果等价于产生多个索引。

索引下推:MySQL 5.6引入了索引下推优化,可以在索引遍历过程中,对索引中包含的字段先做判断,过滤掉不符合条件的记录,减少回表字数。

索引维护:B+树为了维护索引有序性涉及到页分裂跟页合并。增删数据时需考虑页空间利用率。

自增主键:一般会建立与业务无关的自增主键,不会触发叶子节点分裂。

延迟关联:通过使用覆盖索引查询返回需要的主键,再根据主键关联原表获得需要的数据。

数据库三大范式

第一范式:数据库表的每列都是不可在分割的

第二范式:关系模式必须满足第一范式,并且所有非主属性都完全依赖于主码

第三范式:关系模型满足第二范式,所有非主属性对任何候选关键字都不存在传递依赖。即每个属性都跟主键有直接关系而不是间接关系

查询流程是什么

简单来说分为五步:① 客户端发送一条查询给服务器。② 服务器先检查查询缓存,如果命中了缓存则立刻返回存储在缓存中的结果,否则进入下一阶段。③ 服务器端进行 SQL 解析、预处理,再由优化器生成对应的执行计划。④ MySQL 根据优化器生成的执行计划,调用存储引擎的 API 来执行查询。⑤ 将结果返回给客户端。

drop、delete、truncate的区别

1.delete用来删除表的全部或者一部分数据,执行delete之后,用户需要提交或者回滚来执行删除或者撤销删除,delete命令会触发这个表上所欲的delete触发器

2.truncate删除表中所有数据,这个操作不能回滚,也不会触发表上的触发器,truncate比delete更快,占用的空间更小

3.drop命令从数据库中删除表,所有的数据行,索引和权限也会被删除,所有的DML触发器也不会被触发,这个命令不能进行回滚

因此,在不需要一张表的时候,用drop,向删除部分数据行的时候用delete,想保留表而删除所有数据的时候用truncate

MySQL中的锁

MySQL支持三种层级的锁定,分别为

  1. 表级锁定

MySQL中锁定粒度最大的一种锁,最常使用的MYISAM与INNODB都支持表级锁定。

  1. 页级锁定

是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁,表级锁速度快,但冲突多,行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。

  1. 行级锁定

Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大行级锁不一定比表级锁要好:锁的粒度越细,代价越高,相比表级锁在表的头部直接加锁,行级锁还要扫描找到对应的行对其上锁,这样的代价其实是比较高的,所以表锁和行锁各有所长。

MyISAM中的锁
  1. 虽然MySQL支持表,页,行三级锁定,但MyISAM存储引擎只支持表锁。所以MyISAM的加锁相对比较开销低,但数据操作的并发性能相对就不高。但如果写操作都是尾插入,那还是可以支持一定程度的读写并发
  2. 从MyISAM所支持的锁中也可以看出,MyISAM是一个支持读读并发,但不支持通用读写并发,写写并发的数据库引擎,所以它更适合用于读多写少的应用场合,一般工程中也用的较少。
InnoDB中的锁

该模式下支持的锁实在是太多了,具体如下:

共享锁和排他锁 (Shared and Exclusive Locks)

意向锁(Intention Locks)

记录锁(Record Locks)

间隙锁(Gap Locks)

临键锁 (Next-Key Locks)

插入意向锁(Insert Intention Locks)

主键自增锁 (AUTO-INC Locks)

空间索引断言锁(Predicate Locks for Spatial Indexes)

举个栗子,比如行锁里的共享锁跟排它锁:lock in share modle 共享读锁:

为了确保自己查到的数据没有被其他的事务正在修改,也就是说确保查到的数据是最新的数据,并且不允许其他人来修改数据。但是自己不一定能够修改数据,因为有可能其他的事务也对这些数据使用了 in share mode 的方式上了S 锁。如果不及时的commit 或者rollback 也可能会造成大量的事务等待

for update排它写锁:

为了让自己查到的数据确保是最新数据,并且查到后的数据只允许自己来修改的时候,需要用到for update。相当于一个 update 语句。在业务繁忙的情况下,如果事务没有及时的commit或者rollback 可能会造成其他事务长时间的等待,从而影响数据库的并发使用效率。

Gap Lock间隙锁:

1、行锁只能锁住行,如果在记录之间的间隙插入数据就无法解决了,因此MySQL引入了间隙锁(Gap Lock)。间隙锁是左右开区间。间隙锁之间不会冲突

2、间隙锁和行锁合称NextKeyLock,每个NextKeyLock前开后闭区间

间隙锁加锁原则(学完忘那种):

1、加锁的基本单位是 NextKeyLock,是前开后闭区间。

2、查找过程中访问到的对象才会加锁。

3、索引上的等值查询,给唯一索引加锁的时候,NextKeyLock退化为行锁。

4、索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,NextKeyLock退化为间隙锁。

5、唯一索引上的范围查询会访问到不满足条件的第一个值为止。

MVCC

1、全称Multi-Version Concurrency Control,即多版本并发控制。MVCC是一种并发控制的理念,维持一个数据的多个版本,使得读写操作没有冲突。

2、MVCC在MySQL InnoDB中实现目的主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读。

事务并发的控制有了很多成熟的方案,(悲观并发控制,乐观并发控制多版本并发控制(可以与前两者结合使用))前两种几乎是通过延迟或者终止相应的事务来解决事务之间的,竞争条件来保证事务串行化,多版本控制机制是,每一个写操作都会创建一个新版本的数据,读操作会从有限,多个版本的数据中挑选一个最合适的结果直接返回;底层是通过在每个事务下写一个快照来实现的

MySQL InnoDB下的当前读和快照读

  • 当前读:像select lock in share mode(共享锁)、select for update、insert、delete(排他锁)这些操作是一种当前读,就是它读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取记录进行加锁(当前读可以被认为是悲观锁的具体功能实现)
  • 快照读:不加锁的select就是快照读,即不加锁的非阻塞读;快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读;之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但在很多情况下,避免了加锁的操作,降低了开销;既然是基于多版本,即快照读可能读到的并不一定是数据的最新版本,而可能是之前的历史版本。快照读就是mvcc思想在mysql的具体非阻塞读功能实现,mvcc的目的就是为了实现读-写冲突不加锁,提高并发读写性能,而这个读指的就是快照读。快照读就是MySQL为我们实现mvcc理想模型的器重你一个具体非阻塞读功能

MVCC的实现原理

MVCC实现原理主要是依赖记录中的四个隐式字段、undo日志、Consistent Read View来实现的

四个隐式字段:

  1. DB_TRX_ID:

6byte,最近修改(修改/插入)事务ID:记录创建这条记录/最后一次修改该记录的事务ID

2、DB_ROLL_PTR

7byte,回滚指针,指向这条记录的上一个版本(存储于rollback segment里)

3、DB_ROW_ID

6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引

4、FLAG

一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了

事务对一条记录的修改,会导致该记录的undo log成为一条记录版本线性表(链表),undo log的链首就是最新的旧记录,链尾就是最早的旧记录。

undo日志:此知识点上文已经说过了,对MVCC有帮助的实质是update undo log,undo log实际上就是存在rollback segment中旧记录链。

一致读视图 Consistent Read View:Read View是事务进行快照读操作的时候生产的读视图(Read View),在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID(InnoDB里面每个事务有一个唯一的事务ID,叫作transaction id。它是在事务开始的时候向InnoDB的事务系统申请的,是按申请顺序严格递增的)。拿着这个ID跟记录中ID对比进行选择性展示,这里说下大致的思维

你可以简单的理解为MVCC为每一行增加了两个隐藏字段,两个字段分别保存了这个行的当前事务ID跟行的删除事务ID

缓冲池

应用系统分层架构,为了加速数据访问,会把最常访问的数据,放在缓存(cache)里,避免每次都去访问数据库。操作系统,会有缓冲池(buffer pool)机制,避免每次访问磁盘,以加速数据的访问。MySQL作为一个存储系统,同样具有缓冲池(buffer pool)机制,以避免每次查询数据都进行磁盘IO,主要作用:

1、存在的意义是加速查询

2、缓冲池(buffer pool) 是一种常见的降低磁盘访问 的机制;

3、缓冲池通常以页(page 16K)为单位缓存数据;

4、缓冲池的常见管理算法是LRU,memcache,OS,InnoDB都使用了这种算法;

5、InnoDB对普通LRU进行了优化:将缓冲池分为老生代新生代,入缓冲池的页,优先进入老生代,该页被访问,才进入新生代,以解决预读失效的问题页被访问。且在老生代停留时间超过配置阈值的,才进入新生代,以解决批量数据访问,大量热数据淘汰的问题

预读失效

由于预读(Read-Ahead),提前把页放入了缓冲池,但最终MySQL并没有从页中读取数据,称为预读失效

缓冲池污染

当某一个SQL语句,要批量扫描大量数据时,可能导致把缓冲池的所有页都替换出去,导致大量热数据被换出,MySQL性能急剧下降,这种情况叫缓冲池污染。解决办法:加入老生代停留时间窗口策略后,短时间内被大量加载的页,并不会立刻插入新生代头部,而是优先淘汰那些,短期内仅仅访问了一次的页。

table瘦身

空洞

mysql执行delete命令其实只是把记录的位置,或者数据页标记为了可复用,但磁盘文件的大小是不会变的,通过delete命令是不能回收表空间的,这些可以复用,而没有被使用的空间,看起来就像是空洞。插入时候引发分裂同样会产生空洞

重建表

  1. 新建一个跟A表结构相同的表B

  2. 按照主键ID将A数据一行行读取同步到表B

  3. 用表B替换表A实现效果上的瘦身

    指令:1、alter table A engine =InnoDB,慎用2、开源工具:Github:gh-ost

Count()

性能来说:由好到坏:count(字段)<count(主键id)<count(1)=count(*)

随机查询

select word from words order by rand() limit 3;

直接使用order by rand(),explain 这个语句发现需要using temporary和using filesort,查询的代价比较大。

exist和in对比

  1. in查询时首先查询子查询的表,然后将内表和外表做一个笛卡尔积,然后按照条件进行筛选
  2. 子查询使用exists,会先进行主查询,将查询到的每行数据循环带入子查询校验是否存在,过滤出整体的返回数据
  3. 两表大小相当,in和exists差别不大。内表大,用exists效率较高;内表小,用in效率较高
  4. 查询用not in那么内外表都进行全表扫描,没有用到索引;而not exists的子查询依然能用到表上的索引。not exists都比not in要快

mysql中,索引,主键,唯一索引,联合索引的区别,对数据库的性能有什么影响(从读写两方面)

索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。

普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。

普通索引允许被索引的数据列包含重复的值。如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。也就是说,唯一索引可以保证数据记录的唯一性。

主键,是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字 PRIMARY KEY 来创建。

索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引,这就是联合索引。

索引可以极大的提高数据的查询速度,但是会降低插入、删除、更新表的速度,因为在执行这些写操作时,还要操作索引文件

SQL注入漏洞产生的原因?如何防止?

SQL注入产生的原因:程序开发过程中不注意规范书写sql语句和对特殊字符进行过滤,导致客户端可以通过全局变量POST和GET提交一些SQL语句正常执行

防止SQL注入的方式:

  1. 开启配置文件中的magic_quotes_gpc和magic_runtime设置

  2. 执行sql语句时使用addslashes进行sql语句转换

  3. sql语句书写尽量不要省略双引号和单引号

  4. 过滤掉sql语句中的一些关键字:update、insert、delete、select、*;

  5. 提高数据库表和字段的命名技巧,对一些重要的字段根据程序的特点命名,区不易被猜到的

脏读、幻读、不可重复读

脏读:一个事务读取到另一个事务未提交的数据

不可重复读:一个事务对同一行数据重复读取两次,但得到的结果不同

幻读:只一个事务执行两次查询,第二次的查询结果包含了第一次查询中没有出现的数据

丢失更新:两个事务同时更新同一行数据,后提交的事务将之前提交的事务的数据覆盖了

mysql中记录货币用什么字段好

货币在数据库中mysql常用decimal和numric类型表示,这两种类型被MYSQL实现为同样的类型。他们被用于保存值,该值得准确精度是极其重要的值,例如和金钱有关的数据

salary DECIMAL(9,2)

在这个例子中,9(precision)代表将被用于存储值的总的小数位数,而2(scale)代表将被用于存储小数点后的位数。因此,在这种情况下,能被存储在salary列中的值的范围是从-9999999.99到9999999.99。

decimal和numeric值作为字符串存储,而不是作为二进制浮点数,以便保存那些值得小数精度

为什么不使用float和double的原因

因为double和float是二进制存储的,所以有一定的误差

覆盖索引

当我们想做到不回表,在自己的索引上就可以查到自己想要的,那么就不用回表了,由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段

联合索引

还是商品表举例,我们需要根据他的名称,去查他的库存,假设这是一个很高频的查询请求,你会怎么建立索引呢?

大家可以思考上面的回表的消耗对SQL进行优化。

是的建立一个,名称和库存的联合索引,这样名称查出来就可以看到库存了,不需要查出id之后去回表再查询库存了,联合索引在我们开发过程中也是常见的,但是并不是可以一直建立的,大家要思考索引占据的空间。

唯一索引和普通索引的选择

对于唯一索引来说,所有的更新操作都要先判断这个操作是否违反唯一性约束。

要判断表中是否存在这个数据,而这必须要将数据页读入内存才能判断,如果都已经读入到内存了,那直接更新内存会更快,就没必要使用change buffer了。

因此,唯一索引的更新就不能使用change buffer,实际上也只有普通索引可以使用。

很长的字段,想做索引我们怎么去优化它呢?

答:前缀索引

InnoDB设计图

SQL选用索引的执行成本如何计算

  • IO 成本: 即从磁盘把数据加载到内存的成本,默认情况下,读取数据页的 IO 成本是 1,MySQL 是以页的形式读取数据的,即当用到某个数据时,并不会只读取这个数据,而会把这个数据相邻的数据也一起读到内存中,这就是有名的程序局部性原理,所以 MySQL 每次会读取一整页,一页的成本就是 1。所以 IO 的成本主要和页的大小有关
  • CPU 成本:将数据读入内存后,还要检测数据是否满足条件和排序等 CPU 操作的成本,显然它与行数有关,默认情况下,检测记录的成本是 0.2。
  1. 即上述所说,索引能极大地减少扫描行数
  2. 索引可以帮助服务器避免排序和临时表
  3. 索引可以将随机 IO 变成顺序 IO

索引设计准则

如果一个查询满足三星索引中三颗星的所有索引条件,理论上可以认为我们设计的索引是最好的索引。什么是三星索引

  1. 第一颗星:WHERE 后面参与查询的列可以组成了单列索引或联合索引
  2. 第二颗星:避免排序,即如果 SQL 语句中出现 order by colulmn,那么取出的结果集就已经是按照 column 排序好的,不需要再生成临时表
  3. 第三颗星:SELECT 对应的列应该尽量是索引列,即尽量避免回表查询。

B+树

使用B+树的原因和磁盘存取原理有很大的关系,由于存储
介质和机械运动耗费,磁盘的存取速度往往是主存的几百份
之一,为了提高效率,磁盘往往不是严格按需读取,而是每次
都会预读,即使只需要一个字节,磁盘也会从这个位置开始
顺序向后读取一定长度的数据放入内存。这是根据著名的
局限性原理:当一个数据被用到时,其附近的数据通常会
马上被用到。
预读可以提高IO效率,预读的长度一般为页的整数倍,页是计算机
管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区
分割为连续的大小相等的块,每个存储块称为一页(4k),主存和
磁盘以页为单位交换数据。当程序要读取的数据不在主存中时,会
发生一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到
数据的起始位置并向后连续读取一页或几页载入内存,然后异常返回
数据库巧妙的利用了磁盘预读原理,将一个节点的大小设为等于一个页
,这样每个节点只需要一次IO就可以完全载入;
每次新建节点时,直接申请一个页的空间,这样就保证了一个节点
物理上也存储在一个页内,加上之前计算机存储分配都是按页对齐的
就实现了一个node只需要一次IO一次检索最多需要h-1次IO,
而红黑树的高度高很多,逻辑上很近的点物理上很远。

为什么要有内存管理:因为用得到的数据量的大小远远大于内存的大小,虚拟地址就是将程序用到的数据进行划分,暂时用不到的放到磁盘中,用到的放在内存
页式内存管理:虚拟地址位于程序和物理内存之间,程序只能看见虚拟地址不能直接访问物理内存。每个程序都有自己独立的进程地址空间(虚拟地址)。分段和分页就是为了解决怎么从虚拟地址映射到物理地址,因为程序最后是运行在物理内存中。分页机制就是:把内存地址空间分成若干个很小的固定大小的页,每一页的大小由内存决定,提高内存和磁盘的利用率索引和页的关系:一般来说,索引本身很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。而IO存取消耗太大,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘IO的渐进复杂度为了达到这个目的磁盘按需读取,每次都会预读的长度一般为页的整数倍而且数据库系统将一个节点的大小设为等于一个页,这样每个节点只需要一次IO就可以完全载入。

查询

完整性

覆盖索引

范围

自适应哈希索引

异步复制,

select MAX(height) from users where height < (select MAX(height) from users );
select top 1 height from users where height not in (select MAX(height) from users) order by height desc;

select * from score where grade = (select grade from score where grade < (select max(grade) from score ) limit 1);

Mysql主从复制

MySQL主从复制是其最重要的功能之一。主从复制是指一台服务器充当主数据库服务器,另一台或多台服务器充当从数据库服务器,主服务器中的数据自动复制到从服务器之中。对于多级复制,数据库服务器即可充当主机,也可充当从机。MySQL主从复制的基础是主服务器对数据库修改记录二进制日志,从服务器通过主服务器的二进制日志自动执行更新。

MySQL主从复制的两种情况:同步复制和异步复制,实际复制架构中大部分为异步复制。

复制的基本过程如下:

  • Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容。
  • Master接收到来自Slave的IO进程的请求后,负责复制的IO进程会根据请求信息读取日志指定位置之后的日志信息,返回给Slave的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置。
  • Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log的哪个位置开始往后的日志内容,请发给我”。
  • Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行。

数据库水平切分与垂直切分

垂直拆分就是要把表按模块划分到不同数据库表中(当然原则还是不破坏第三范式),这种拆分在大型网站的演变过程中是很常见的。当一个网站还在很小的时候,只有小量的人来开发和维护,各模块和表都在一起,当网站不断丰富和壮大的时候,也会变成多个子系统来支撑,这时就有按模块和功能把表划分出来的需求。其实,相对于垂直切分更进一步的是服务化改造,说得简单就是要把原来强耦合的系统拆分成多个弱耦合的服务,通过服务间的调用来满足业务需求看,因此表拆出来后要通过服务的形式暴露出去,而不是直接调用不同模块的表,淘宝在架构不断演变过程,最重要的一环就是服务化改造,把用户、交易、店铺、宝贝这些核心的概念抽取成独立的服务,也非常有利于进行局部的优化和治理,保障核心模块的稳定性。

垂直拆分:单表大数据量依然存在性能瓶颈

水平拆分,上面谈到垂直切分只是把表按模块划分到不同数据库,但没有解决单表大数据量的问题,而水平切分就是要把一个表按照某种规则把数据划分到不同表或数据库里。例如像计费系统,通过按时间来划分表就比较合适,因为系统都是处理某一时间段的数据。而像SaaS应用,通过按用户维度来划分数据比较合适,因为用户与用户之间的隔离的,一般不存在处理多个用户数据的情况,简单的按user_id范围来水平切分。

通俗理解:水平拆分行,行数据拆分到不同表中, 垂直拆分列,表数据拆分到不同表中

数据库高并发的解决方案

  1. 在web服务框架中加入缓存。在服务器与数据库层之间加入缓存层,将高频访问的数据存入缓存中,减少数据库的读取负担。

  2. 增加数据库索引。提高查询速度。(不过索引太多会导致速度变慢,并且数据库的写入会导致索引的更新,也会导致速度变慢)

  3. 主从读写分离,让主服务器负责写,从服务器负责读。

  4. 将数据库进行拆分,使得数据库的表尽可能小,提高查询的速度。

  5. 使用分布式架构,分散计算压力。

数据库的七种锁

  • 行锁(Record Locks)
  • 间隙锁(Gap Locks)
  • 临键锁(Next-key Locks)
  • 共享锁/排他锁(Shared and Exclusive Locks)
  • 意向共享锁/意向排他锁(Intention Shared and Exclusive Locks)
  • 插入意向锁(Insert Intention Locks)
  • 自增锁(Auto-inc Locks)
  • 行锁:行锁一定是作用在索引上的。
  • 间隙锁:锁在本质上是不区分共享间隙锁或互斥间隙锁的,而且间隙锁是不互斥的,即两个事务可以同时持有包含共同间隙的间隙锁。这里的共同间隙包括两种场景:其一是两个间隙锁的间隙区间完全一样;其二是一个间隙锁包含的间隙区间是另一个间隙锁包含间隙区间子集。间隙锁本质上是用于阻止其他事务在该间隙内插入新记录,而自身事务是允许在该间隙内插入数据的。也就是说间隙锁的应用场景包括并发读取、并发更新、并发删除和并发插入。在RU和RC两种隔离级别下,即使你使用select …in share mode或select … for update,也无法防止幻读(读后写的场景)。因为这两种隔离级别下只会有行锁,而不会有间隙锁。这也是为什么示例中要规定隔离级别为RR的原因。
  • 临键锁:临键锁是行锁+间隙锁,即临键锁是是一个左开右闭的区间,比如(3,5]。InnoDB的默认事务隔离级别是RR,在这种级别下,如果你使用select … in share mode或者select … for update语句,那么InnoDB会使用临键锁,因而可以防止幻读;但即使你的隔离级别是RR,如果你这是使用普通的select语句,那么InnoDB将是快照读,不会使用任何锁,因而还是无法防止幻读
  • 共享锁/排他锁:共享锁/排他锁都只是行锁,与间隙锁无关,这一点很重要,后面还会强调这一点。其中共享锁是一个事务并发读取某一行记录所需要持有的锁,比如select … in share mode;排他锁是一个事务并发更新或删除某一行记录所需要持有的锁,比如select … for update。不过这里需要重点说明的是,尽管共享锁/排他锁是行锁,与间隙锁无关,但一个事务在请求共享锁/排他锁时,获取到的结果却可能是行锁,也可能是间隙锁,也可能是临键锁,这取决于数据库的隔离级别以及查询的数据是否存在。关于这一点,后面分析场景一和场景二的时候还会提到。
  • 意向共享锁/意向排他锁:意向共享锁/意向排他锁属于表锁,且取得意向共享锁/意向排他锁是取得共享锁/排他锁的前置条件
  • 插入意向锁:插入意向锁是一种特殊的间隙锁,但不同于间隙锁的是,该锁只用于并发插入操作。如果说间隙锁锁住的是一个区间,那么插入意向锁锁住的就是一个点。因而从这个角度来说,插入意向锁确实是一种特殊的间隙锁。与间隙锁的另一个非常重要的差别是:尽管插入意向锁也属于间隙锁,但两个事务却不能在同一时间内一个拥有间隙锁,另一个拥有该间隙区间内的插入意向锁(当然,插入意向锁如果不在间隙锁区间内则是可以的)。这里我们再回顾一下共享锁和排他锁:共享锁用于读取操作,而排他锁是用于更新删除操作。也就是说插入意向锁、共享锁和排他锁涵盖了常用的增删改查四个动作。
  • 自增锁:增锁是一种特殊的表级锁,主要用于事务中插入自增字段,也就是我们最常用的自增主键id。

通过innodb_autoinc_lock_mode参数可以设置自增主键的生成策略。为了便于介绍

innodb_autoinc_lock_mode参数,我们先将需要用到自增锁的Insert语句进行分类:

【数据库】吐血整理---数据库合集相关推荐

  1. 【redis】吐血整理---redis合集

    文章目录 Redis 1.项目为什么用到redis? 2.redis的数据结构? 应用场景 小结 Bitmap: HyperLogLog: Geospatial: pub/sub: Pipeline: ...

  2. 数据库查询某一列大写转化小写字母表示_算法/开发 面试必看! 【数据库】面试题合集...

    本合集整理了计算机专业相关算法/开发面试中遇到的[数据库]相关面试题,后续会不断更新,有需要的小伙伴可以点赞or收藏随时查阅哦! Q:数据库四大特性ACID? Atomicity(原子性):一个事务( ...

  3. 2019年7月抖音热门音乐整理精选合集- 免费下载

    抖音最新7月份整理的超好听音乐合集 小编已打包 分享给共同爱好的朋友们 有需要的快去下载吧, 很担心会被和谐 熬夜整理,很多音乐都是我自费购买的无损音乐 就为了给大家一个完美的音质. 下载地址 链接: ...

  4. 数据库常考选择题合集

    抽时间整理了75个数据库的选择题,应该够宝子们考前复习了(接下来我还会整理填空题和后面的大题哦~) 关注雨桐Miracle不迷路哦(。→v←。) 选择题 1.在数据管理技术的发展过程中,经历了人工管理 ...

  5. Mysql数据库使用及其问题合集一

    问题一: 解决办法: mysql登录 修改登录密码 navicat显示连接成功 这里要注意,密码更新下,修改为你刚才新设置的密码!!! 问题二: 这种情况 提示里说是语法错误,就应该根据你的mysql ...

  6. 数据库知识整理 - 数据库完整性

    主要内容 实体完整性 小拓展:索引的应用 参照完整性 用户定义的完整性 1. 属性上的约束条件 2. 元组上的约束条件 完整性约束命名子句 域中的完整性约束条件 断言 触发器 1. 定义触发器 2. ...

  7. 【2021新版】一线大厂 Go 高频面试题,整理分析合集

    随着云计算时代的到来,Go 的应用越来越广泛,已然成为首选编程语言,而且,薪资也水涨船高. 以字节跳动为例,Go 语言是字节跳动内部使用最多的编程语言.为啥?因为字节跳动更看重效率,上手简单,学习难度 ...

  8. ZBrush笔刷整理大合集

  9. 开发者社区精选直播合集一览

    简介:本合集囊括了:AI.架构师. Serverless .AIoT.DevOps.容器化.机器学习.云计算.K8s.微服务.云原生.视觉AI.大数据.小程序.物联网等各种主题直播合集,让你一次看个够 ...

最新文章

  1. Git -- 基本操作 之 版本回退
  2. wxWidgets:wxAuiTabArt类用法
  3. android 开发艾特功能,Android Binder
  4. Flink的状态一致性
  5. windows apche php mysql zend_Windows XP上安装配置 Apache+PHP+Mysql+Zend
  6. springMVC操作mongoDB增删改查
  7. 操作自定义属性、H5自定义属性
  8. 最近任务 react文章列表
  9. 拷贝出师表到另一个文件,恢复顺序
  10. Android 仿支付宝9.0芝麻信用分效果
  11. linux c 获取文件大小
  12. HDU 6975 Forgiving Matching 快速傅里叶变换处理带通配符字符串匹配
  13. java取余(java取余数的函数)
  14. 设计评审CheckList
  15. 响应式织梦模板装修装饰设计类网站
  16. 图片转pdf/pdf多文件合并,在线一键完成
  17. 冲突域和碰撞域的理解
  18. PCL1.10.1+VS2019+Qt5.14.2下载、安装及配置(强迫症福音~使用的软件均为最新版本)
  19. Java复数类实现加减乘除运算
  20. (笔记)数据结构--抽象数据类型的定义

热门文章

  1. 连续型随机变量在某一点的概率值为0 ← 随机过程
  2. 使用Busybox制作最小文件系统并烧写入开发板
  3. 什么是MES(Manufacturing Execution System)
  4. MapReduce工作笔记——目录
  5. ie检查html快捷键,IE浏览器快捷键大全
  6. Python实现微信发送文件实例
  7. 算法 |【实验5.2】1-深度优先搜索暴力求解旅行商问题
  8. CFA报考丨含金量最高的证书,在校期间千万别错过!
  9. MaxCompute Studio
  10. Spring Cloud动画视频笔记