MySQL八股文背诵版2:事务特性,并发一致性,隔离级别,MVCC,锁,共享 排它,行 表锁,意向锁,记录 间隙 临键锁,乐观 悲观 死锁,约束,连接查询,in和exists,分表分库,主从复制

章目录

https://blog.youkuaiyun.com/weixin_41543483/article/details/120310282

数据库的事务***

什么是数据库的事务?

数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。

事务的四大特性是什么?

  • 原子性:原子性是指包含事务的操作要么全部执行成功,要么全部失败回滚。
  • 一致性:一致性指事务在执行前后状态是一致的。
  • 隔离性:一个事务所进行的修改在最终提交之前,对其他事务是不可见的。
  • 持久性:数据一旦提交,其所作的修改将永久地保存到数据库中。

数据库的并发一致性问题?

当多个事务并发执行时,可能会出现以下问题:

  • 脏读:事务A更新了数据,但还没有提交,这时事务B读取到事务A更新后的数据,然后事务A回滚了,事务B读取到的数据就成为脏数据了。

  • 不可重复读:事务A对数据进行多次读取事务B在事务A多次读取的过程中执行了更新操作并提交了,导致

    • 事务A多次读取到的数据并不一致
  • 幻读:事务A在读取数据后,事务B向事务A读取的数据中插入了几条数据

    • 事务A再次读取数据时发现多了几条数据,和之前读取的数据不一致。
  • 丢失修改:事务A和事务B都对同一个数据进行修改,

    • 事务A先修改,事务B随后修改,事务B的修改覆盖了事务A的修改。
      不可重复度和幻读看起来比较像,它们主要的区别是:

    • 不可重复读中发现数据不一致主要是数据被更新了

    • 幻读中发现数据不一致主要是数据增多或者减少了

数据库的隔离级别有哪些?

  • 未提交读:一个事务在提交前,它的修改对其他事务也是可见的。
  • 提交读:一个事务提交之后,它的修改才能被其他事务看到。
  • 可重复读:在同一个事务中多次读取到的数据是一致的。
  • 串行化:需要加锁实现,会强制事务串行执行。
    数据库的隔离级别分别可以解决数据库的脏读、不可重复读、幻读等问题。
隔离级别脏读不可重复读(修改)幻读(插入)
未提交读允许允许允许
提交读不允许允许允许
可重复读不允许不允许允许
串行化不允许不允许不允许

隔离级别如何实现的?

事务的隔离机制主要是依靠锁机制和MVCC(多版本并发控制)实现的

提交读和可重复读可以通过MVCC实现,

串行化可以通过锁机制实现。

什么是MVCC 多版本并发控制?

当前读 和 快照读

MVCC(multiple version concurrent control)是一种控制并发的方法,主要用来提高数据库的并发性能

在了解MVCC时应该先了解 当前读 和 快照读。

  • 当前读:读取的是数据库的最新版本,并且在读取时要保证其他事务不会修该当前记录,所以会对读取的记录加锁。
  • 快照读不加锁读取操作即为快照读,使用MVCC来读取快照中的数据,避免加锁带来的性能损耗。
    可以看到MVCC的作用就是在不加锁的情况下,解决数据库读写冲突问题,并且解决脏读、幻读、不可重复读等问题,但是不能解决丢失修改问题。
MVCC的实现原理:
  • 版本号
    系统版本号:是一个自增的ID,每开启一个事务,系统版本号都会递增。
    事务版本号:事务版本号就是事务开始时的系统版本号,可以通过事务版本号的大小判断事务的时间顺序。

  • 行记录隐藏的列

    • DB_ROW_ID:所需空间6byte隐含的自增ID,用来生成聚簇索引,
      • 如果数据表没有指定聚簇索引InnoDB会利用这个隐藏ID创建聚簇索引
    • DB_TRX_ID:所需空间6byte,最近修改的事务ID,记录创建这条记录的事务ID。
    • DB_ROLL_PTR:所需空间7byte回滚指针,指向这条记录的上一个版本。

    它们大致长这样,省略了具体字段的值。

  • DB_ROW_ID 自增ID

  • DB_TRX_ID 这条记录的事务ID

  • DB_ROLL_PTR 回滚指针,这条记录的上一个版本

img

undo日志
  • MVCC使用到的快照会存储在Undo日志中,该日志通过回滚指针将一个一个数据行的所有快照连接起来。它们大致长这样

img

举一个例子说明下,比如最开始的某条记录长这样

img

现在来了一个事务对他的年龄字段进行了修改,就变成了这样

img

现在又来了一个事务对它的性别进行了修改,它又变成了这样

img

从上面的分析可以看出,事务对同一记录的修改,每条记录会在Undo日志中连接成一个线性表,在表头的就是最新的旧记录。

InnoDB的工作流程

在重复读的隔离级别下,InnoDB的工作流程:

  • SELECT
    作为查询的结果满足两个条件:
    1. 当前事务所要查询的数据行快照的创建版本号必须小于当前事务的版本号,这样做的目的是保证当前事务读取的数据行的快照要么是在当前事务开始前就已经存在的,要么就是当前事务自身插入或者修改过的
      1. 要么是在当前事务开始前就已经存在的
      2. 要么就是当前事务自身插入或者修改过的
    2. 当前事务所要读取的数据行快照的删除版本号必须是大于当前事务的版本号,如果是小于等于的话,表示该数据行快照已经被删除,不能读取。
  • INSERT
    将当前系统版本号作为数据行快照的创建版本号
  • DELETE
    将当前系统版本号作为数据行快照的删除版本号
  • UPDATE
    保存当前系统版本号为更新前的数据行快照创建行版本号,并保存当前系统版本号为更新后的数据行快照的删除版本号,其实就是,先删除再插入即为更新

总结一下,MVCC的作用是在避免加锁的情况下最大限度的解决读写并发冲突的问题,它可以实现提交读和可重复读两个隔离级。

数据库的锁***

什么是数据库的锁?

当数据库有并发事务的时候,保证数据访问顺序的机制称为锁机制。

数据库的锁与隔离级别的关系?

隔离级别实现方式
未提交读总是读取最新的数据,无需加锁
提交读读取数据时加共享锁,读取数据后释放共享锁
可重复读读取数据时加共享锁,事务结束后释放共享锁
串行化锁定整个范围的键,一直持有锁直到事务结束

数据库锁的类型有哪些?表 行 页面

按照锁的粒度可以将MySQL锁分为三种:

MySQL锁类别资源开销加锁速度是否会出现死锁锁的粒度并发度
表级锁不会
行级锁
页面锁一般一般不会一般一般

MyISAM默认采用表级锁,InnoDB默认采用行级锁。

共享锁,排它锁

从锁的类别上区别可以分为共享锁和排他锁

  • 共享锁:共享锁又称读锁,简写为S锁,一个事务对一个数据对象加了S锁,
    • 可以对这个数据对象进行读取操作,但不能进行更新操作。
    • 并且在加锁期间其他事务只能对这个数据对象加S锁,不能加X锁。
  • 排他锁:排他锁又称为写锁,简写为X锁,一个事务对一个数据对象加了X锁,可以对这个对象进行读取和更新操作,加锁期间,其他事务不能对该数据对象进行加X锁或S锁。

img

  • 即:写锁都互斥。
  • 读锁:对读 可以。

MySQL中InnoDB引擎的行锁模式及其是如何实现的?

行锁 和 意向锁 兼容

行锁模式

在存在行锁和表锁的情况下,一个事务想对某个表加X锁时,需要先检查是否有其他事务对这个表加了锁或对这个表的某一行加了锁

  • 对表的每一行都进行检测一次这是非常低效率的,为了解决这种问题,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁,两种意向锁都是表锁。
    • 意向共享锁 :简称IS锁,一个事务打算给数据行加共享锁前必须先获得该表的IS锁
    • 简称IX锁,一个事务打算给数据行加排他锁前必须先获得该表的IX锁
      有了意向锁,一个事务想对某个表加X锁,只需要检查是否有其他事务对这个表加了X/IX/S/IS锁即可。
      锁的兼容性如下:

img

  • IX,意向排它锁,对意向排它锁 可兼容。对意向共享锁,可兼容。

  • S 共享锁,多共享锁 可兼容,共享锁 对 意向共享锁 可兼容。

  • IS,意向共享锁,对 意向排它锁 可兼容,对 共享锁,意向共享锁 可兼容。

行锁的实现方式:InnoDB的行锁是通过给索引项加锁实现的,如果没有索引,InnoDB将通过隐藏的聚簇索引来对记录进行加锁。

记录 间隙 临键 锁

InnoDB行锁主要分三种情况:

  • Record lock:对索引项加锁
  • Grap lock:对索引之间的“间隙”、第一条记录前的“间隙”或最后一条后的间隙加锁。
  • Next-key lock:前两种放入组合,对记录及前面的间隙加锁
    • 临键锁:记录锁(record lock)与间隙锁(gap lock)的结合
Graph
n.
图表,曲线图;坐标图;代表声音单位(或其他言语特征)的书写符号
v.
用图表表示

InnoDB行锁的特性:如果不通过索引条件检索数据,那么InnoDB将对表中所有记录加锁,实际产生的效果和表锁是一样的。

MVCC不能解决幻读问题,在可重复读隔离级别下,使用MVCC+Next-Key Locks 可以解决幻读问题。

  • 不能解决幻读

什么是数据库的 乐观锁 和 悲观锁,如何实现?

乐观锁:系统假设数据的更新在大多时候是不会产生冲突的,所以数据库只在更新操作提交的时候对数据检测冲突,如果存在冲突,则数据更新失败。

乐观锁实现方式:一般通过版本号和CAS算法实现

悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据库完整性的操作。通俗讲就是每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁。

悲观锁的实现方式:通过数据库的锁机制实现,对查询语句添加for update

什么是死锁,如何避免?

死锁是指两个或者两个以上进程在执行优化过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象。在MySQL中,**MyISAM是一次性获得所需的全部锁,要么全部满足,要么等待,所以不会出现死锁。**在InnoDB存储引擎中,除了单个SQL组成的事物外,锁都是逐步获得的,所以存在死锁问题。

如何避免MySQL发生死锁或者锁冲突:

如果不同的程序并发存取多个表,尽量以相同的顺序访问表

在程序以批量方式处理数据的时候,如果已经对数据排序,尽量保证每个线程按照固定顺序来处理记录,

在事务中,如果需要更新记录,

  • 应直接申请足够级别的排他锁,
  • 而不应该先申请共享锁,更新时再申请排他锁,
    因为在当前用户申请排他锁时,其他事务可能已经获得了相同记录的共享锁,从而造成锁冲突或者死锁
  • 因为排它锁 和 其他锁 不能同时存在。

尽量使用较低的隔离级别

尽量使用索引访问数据,使加锁更加准确,从而减少锁冲突的机会

合理选择事务大小,小事务发生锁冲突的概率更低

尽量使用相等的条件访问数据,可以避免Next-Key锁对并发插入的影响

不要申请超过实际需要的锁级别查询是尽量不要显示加锁

对于一些特定的事务,可以表锁来提高处理速度或减少死锁的概率

SQL语句基础知识及优化

SQL语句主要分为哪几类?*

  • 数据据定义语言DDL(Data Definition Language):
    • 主要有CREATE,DROP,ALTER等对逻辑结构有操作的,
    • 包括表结构、视图和索引。
  • 数据库查询语言DQL(Data Query Language):主要以SELECT为主
  • 数据操纵语言DML(Data Manipulation Language):主要包括INSERT,UPDATE,DELETE
  • 数据控制功能DCL(Data Control Language):主要是权限控制能操作,
    • 包括GRANT,REVOKE,COMMIT,ROLLBACK等。

开启MySQL事务的方法:

开启MySQL事务的方法:

显式事务。使用START TRANSACTIONBEGIN命令。
start transation;
begin;

隐式事务。使用SET AUTOCOMMIT OFF命令。
set autocommit = 0;
SET autocommit = OFF;

set autocommit off; 关闭自动提交事务 
set autocommit on;开启自动提交事务

SQL约束有哪些?主外 唯一 默认 check**

  • 主键约束:主键为在表中存在一列或者多列的组合,能唯一标识表中的每一行。一个表只有一个主键,并且主键约束的列不能为空。
  • 外键约束:外键约束是指用于在两个表之间建立关系,需要指定引用主表的哪一列。只有主表的主键可以被从表用作外键,被约束的从表的列可以不是主键,所以创建外键约束需要先定义主表的主键,然后定义从表的外键。
  • 唯一约束:确保表中的一列数据没有相同的值,一个表可以定义多个唯一约束。
  • 默认约束:在插入新数据时,如果该行没有指定数据,系统将默认值赋给该行,
    • 如果没有设置没默认值,则为NULL。
  • Check约束:Check会通过逻辑表达式来判断数据的有效性,用来限制输入一列或者多列的值的范围。在列更新数据时,输入的内容必须满足Check约束的条件。

什么是子查询?(age,sex) **

子查询:把一个查询的结果在另一个查询中使用

  • 标量子查询:指子查询返回的是一个值,可以使用 =,>,<,>=,<=,<>等操作符对子查询标量结果进行比较,一般子查询会放在比较式的右侧。
SELECT * 
FROM user 
WHERE age = (
    SELECT max(age) from user
)  //查询年纪最大的人 
  • 列子查询:指子查询的结果是n行一列,一般应用于对表的某个字段进行查询返回。可以使用IN、ANY、SOME和ALL等操作符,不能直接使用
SELECT num1 
FROM table1 
WHERE num1 > ANY (
    SELECT num2 FROM table2
)
  • 行子查询:指子查询返回的结果一行n列
SELECT * 
FROM user 
WHERE (age,sex) = (
	SELECT age,sex 
	FROM user 
	WHERE name="zhangsan"
)
  • 表子查询:指子查询是n行n列的一个数据表
SELECT * 
FROM student 
WHERE (name,age,sex) IN (
    SELECT name,age,sex 
    FROM class1
) 

//在学生表中找到班级在1班的学生

了解MySQL的几种连接查询嘛?***

MySQl的连接查询主要可以分为外连接,内连接,交叉连接

  • 外连接包括左连接和右连接
    • 左连接:查询的结果为两个表匹配到的数据,左表特有的数据,对于右表中不存在的数据使用null填充

img

  • 右连接:查询的结果为两个表匹配到的数据,右表特有的数据,对于左表中不存在的数据使用null填充

img

内连接查询:查询的结果为两个表匹配到的数据

img

  • 交叉连接,使用笛卡尔积的一种连接。
    笛卡尔积:两个集合X和Y的笛卡尔积表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员 。例如:A={a,b},B={0,1,2},A × B = {(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}

举例如下:有两张表分为L表和R表。
L表

AB
a1b1
a2b2
a3b3

R 表

BC
b1c1
b2c2
b4c3
  • 交叉连接:select L.*,R.* from L,R
ABBC
a1b1b1c1
a1b1b2c2
a1b1b4c3
a2b2b1c1
a2b2b2c2
a2b2b4c3
a3b3b1c1
a3b3b2c2
a3b3b4c3

MySQL中in和exists的区别**

in和exists一般用于子查询。

  • 使用exists时会先进行外表查询,将查询到的每行数据带入到内表查询中看是否满足条件
    • 使用in一般会先进行内表查询获取结果集,返回数据。
  • in在内表查询时会用到索引
  • exists仅在内表查询时会用到索引
  • 一般来说,当子查询的结果集比较大,外表较小使用exists效率更高
    • 当子查询查找到的结果集较小,外表较大时,使用in效率更高。
  • 对于not in和not exists,not exists 效率比not in 高,与子查询的结果集无关
    • 因为not in 对于内外表都进行了全表扫描,没有使用到索引
    • not exists 的子查询中可以用到表上的索引。

varchar和char的区别***

  • varchar表示变长,char表示长度固定。当所插入的字符超过他们的长度时,
    • 在严格模式下,会拒绝插入并提示错误信息,
    • 在一般模式下,会截取后插入。如char(5),无论插入的字符长度是多少,长度都是5,插入字符长度小于5,则用空格补充。
    • 对于varchar(5),如果插入的字符长度小于5,则存储的字符长度就是插入字符的长度,不会填充。
  • 存储容量不同,对于char来说,最多能存放的字符个数为255。对于varchar,最多能存放的字符个数是65532。
  • 存储速度不同,char长度固定,存储速度会比varchar快一些,但在空间上会占用额外的空间,属于一种空间换时间的策略。而varchar空间利用率会高些,但存储速度慢,属于一种时间换空间的策略

MySQL中int(10)和char(10)和varchar(10)的区别***

int(10)中的10表示的是显示数据的长度,而char(10)和varchar(10)表示的是存储数据的大小。

drop、delete和truncate的区别**

truncate
英
/trʌŋˈkeɪt/
v.
截断,删节;把……截成平面
dropdeletetruncate
速度逐行删除,慢较快
类型DDLDMLDDL
回滚不可回滚可回滚不可回滚
删除内容删除整个表,数据行、索引都会被删除表结构还在,删除表的一部分或全部数据****表结构还在,删除表的全部数据

一般来讲,删除整个表,使用drop,删除表的部分数据使用delete保留表结构删除表的全部数据使用truncate。

UNION和UNION ALL的区别**

union和union all的作用都是将两个结果集合并到一起。

  • union会对结果去重并排序,union all直接返回合并后的结果,不去重也不进行排序。
  • union all的性能比union性能好。

什么是临时表,什么时候会使用到临时表,什么时候删除临时表?*

MySQL在执行SQL语句的时候会临时创建一些存储中间结果集的表,这种表被称为临时表,临时表只对当前连接可见,在连接关闭后,临时表会被删除并释放空间。
临时表主要分为内存临时表和磁盘临时表两种。内存临时表使用的是MEMORY存储引擎,磁盘临时表使用的是MyISAM存储引擎。
一般在以下几种情况中会使用到临时表:

  • FROM中的子查询
  • DISTINCT查询并加上ORDER BY
  • ORDER BY和GROUP BY的子句不一样时会产生临时表
  • 使用UNION查询会产生临时表

大表数据查询如何进行优化?***

  • 索引优化
  • SQL语句优化
  • 水平拆分
  • 垂直拆分
  • 建立中间表
  • 使用缓存技术
  • 固定长度的表访问起来更快
  • 越小的列访问越快

了解慢日志嘛?统计过慢查询嘛?对慢查询如何优化?***

慢查询一般用于记录执行时间超过某个临界值的SQL语句的日志。

相关参数:

slow_query_log:是否开启慢日志查询,1表示开启,0表示关闭。

slow_query_log_file:MySQL数据库慢查询日志存储路径。

long_query_time:慢查询阈值,当SQL语句查询时间大于阈值,会被记录在日志上。

log_queries_not_using_indexes:未使用索引的查询会被记录到慢查询日志中。

log_output:日志存储方式。“FILE”表示将日志存入文件。“TABLE”表示将日志存入数据库。

如何对慢查询进行优化?

  • 分析语句的执行计划,
  • 查看SQL语句的索引是否命中
  • 优化数据库的结构,将字段很多的表分解成多个表,或者考虑建立中间表。
  • 优化LIMIT分页。

为什么要设置主键?**

主键是唯一区分表中每一行的唯一标识,如果没有主键,更新或者删除表中特定的行会很困难,因为不能唯一准确地标识某一行。

主键一般用自增ID还是UUID?**

使用自增ID的好处:

  • 字段长度较uuid会小很多。
  • 数据库自动编号,按顺序存放,利于检索
  • 无需担心主键重复问题

使用自增ID的缺点:

  • 因为是自增,在某些业务场景下,容易被其他人查到业务量。
  • 发生数据迁移时,或者表合并时会非常麻烦
  • 高并发的场景下,竞争自增锁会降低数据库的吞吐能力

UUID:通用唯一标识码,UUID是基于当前时间、计数器和硬件标识等数据计算生成的。

使用UUID的优点:

  • 唯一标识,不会考虑重复问题,在数据拆分、合并时也能达到全局的唯一性。
  • 可以在应用层生成,提高数据库的吞吐能力。
  • 无需担心业务量泄露的问题。

使用UUID的缺点:

  • 因为UUID是随机生成的,所以会发生随机IO,影响插入速度,并且会造成硬盘的使用率较低。
  • UUID占用空间较大,建立的索引越多,造成的影响越大。
  • UUID之间比较大小较自增ID慢不少,影响查询速度。

最后说下结论,一般情况MySQL推荐使用自增ID。因为在MySQL的InnoDB存储引擎中,主键索引是一种聚簇索引,主键索引的B+树的叶子节点按照顺序存储了主键值及数据,如果主键索引是自增ID,只需要按顺序往后排列即可,如果是UUID,ID是随机生成的,在数据插入时会造成大量的数据移动,产生大量的内存碎片,造成插入性能的下降。

字段为什么要设置成not null? **

  • 空值:对于字符串类型的字段,空值会占用一定的存储空间。虽然空值本身不包含任何字符,但实际上会为它分配一些空间。
  • 下面说反了

首先说一点,NULL和空值是不一样的,空值是不占用空间的,而NULL是占用空间的,所以字段设为NOT NULL后仍然可以插入空值。
字段设置成not null主要有以下几点原因:

  • NULL值会影响一些函数的统计,如count,遇到NULL值,这条记录不会统计在内。
  • B树不存储NULL,所以索引用不到NULL,会造成第一点中说的统计不到的问题。
  • NOT IN子查询在有NULL值的情况下返回的结果都是空值。
    例如user表如下
idusername
0zhangsan
1lisi
2null
select * 
from `user` 
where username NOT IN ( --案例说会返回 zhangsan,但是 not in中有null,会直接返回null

	-- 返回 Null 和 lisi 两条数据
    select username 
    from `user` 
    where id != 0
)

-- 去掉 NOT,案例说 应该返回: lisi和null,但是 会自动去掉。null(id=2的记录)


如果 把ID 改为 空,一切都没问题

,这条查询语句应该查到zhangsan这条数据,但是结果显示为null。

  • MySQL在进行比较的时候,NULL会参与字段的比较,因为NULL是一种比较特殊的数据类型,数据库在处理时需要进行特殊处理,增加了数据库处理记录的复杂性。

如何优化查询过程中的 数据访问?***

从减少数据访问方面考虑:

  • 正确使用索引,尽量做到索引覆盖
  • 优化SQL执行计划

从返回更少的数据方面考虑:

  • 数据分页处理
  • 只返回需要的字段
  • 减少服务器CPU开销方面考虑:

合理使用排序

  • 减少比较的操作
  • 复杂运算在客户端处理
  • 从增加资源方面考虑:

客户端多进程并行访问

  • 数据库并行处理

如何优化长难的查询语句?**

  • 将一个大的查询分解为多个小的查询
  • 分解关联查询,使缓存的效率更高

如何优化LIMTI分页?**

  • 在LIMIT偏移量较大的时候,查询效率会变低,可以记录每次取出的最大ID,下次查询时可以利用ID进行查询
  • 建立复合索引、

如何优化UNION查询 **

如果不需要对结果集进行去重或者排序建议使用UNION ALL,会好一些。

如何优化WHERE子句***

  • 不要在where子句中使用**!=和<>进行不等于判断,这样会导致放弃索引进行全表扫描。**
  • 不要在where子句中使用null或空值判断,尽量设置字段为not null。
  • 尽量使用union all代替or
  • 在where和order by涉及的列建立索引
  • 尽量减少使用in或者not in,会进行全表扫描
  • 在where子句中使用参数会导致全表扫描
  • 避免在where子句中对字段及进行表达式或者函数操作会导致存储引擎放弃索引进而全表扫描

SQL语句执行很慢的原因是什么***

  • 如果SQL语句只是偶尔执行很慢,可能是执行的时候遇到了锁,也可能是redo log日志写满了,要将redo log中的数据同步到磁盘中去。
  • 如果SQL语句一直都很慢,可能是字段上没有索引或者字段有索引但是没用上索引。

SQL语句的执行顺序?*

SELECT DISTINCT 
    select_list
FROM 
    left_table
LEFT JOIN 
    right_table ON join_condition
    
WHERE 
    where_condition 
    
GROUP BY 
    group_by_list 
HAVING 
    having_condition 
    
ORDER BY 
    order_by_condition

执行顺序如下:

img

  • from—on—join—where—order by—distinct—select—having—group by
  • FROM:对SQL语句执行查询时,首先对关键字两边的表**以笛卡尔积的形式执行连接,并产生一个虚表V1。虚表就是视图,**数据会来自多张表的执行结果。
  • ON:对FROM连接的结果进行ON过滤,并创建虚表V2
  • JOIN:将ON过滤后的左表添加进来,并创建新的虚拟表V3
  • WHERE:对虚拟表V3进行WHERE筛选,创建虚拟表V4
  • GROUP BY:对V4中的记录进行分组操作,创建虚拟表V5
  • HAVING:对V5进行过滤,创建虚拟表V6
  • SELECT:将V6中的结果按照SELECT进行筛选,创建虚拟表V7
  • DISTINCT:对V7表中的结果进行去重操作,创建虚拟表V8,
    • 如果使用了GROUP BY子句则无需使用DISTINCT,因为分组的时候是将列中唯一的值分成一组,并且每组只返回一行记录,所以所有的记录都h是不同的。
  • ORDER BY:对V8表中的结果进行排序。

数据库优化

大表如何优化***

  • 限定数据的范围:避免不带任何限制数据范围条件的查询语句。
  • 读写分离:主库负责写,从库负责读。
  • 垂直分表:将一个表按照字段分成多个表,每个表存储其中一部分字段。
  • 水平分表:在同一个数据库内,把一个表的数据按照一定规则拆分到多个表中。
  • 对单表进行优化:对表中的字段、索引、查询SQL进行优化。
  • 添加缓存

什么是垂直 水平分表,垂直 水平分库?***

垂直分表 和 优势

垂直分表:将一个**表按照字段分成多个表,每个表存储其中一部分字段。**一般会将

  • **常用的字段放到一个表中,**将不常用的字段放到另一个表中。

垂直分表的优势

  • 避免IO竞争减少锁表的概率。因为大的字段效率更低,
    • 第一数据量大,需要的读取时间长。
    • 第二,大字段占用的空间更大,单页内存储的行数变少,会使得IO操作增多。
  • 可以更好地提升热门数据的查询效率

垂直分库 和 优势

垂直分库:按照业务对表进行分类,部署到不同的数据库上面,不同的数据库可以放到不同的服务器上面。

垂直分库的优势:

  • 降低业务中的耦合,方便对不同的业务进行分级管理。
  • 可以提升IO、数据库连接数、解决单机硬件资源的瓶颈问题。

垂直拆分的缺点:

垂直拆分(分库、分表)的缺点:

  • 主键出现冗余,需要管理冗余列
  • 事务的处理变得复杂
  • 仍然存在单表数据量过大的问题

水平分表 和 优势

水平分表:在同一个数据库内,把同一个表的数据按照一定规则拆分到多个表中。

水平分表的优势:

  • 解决了单表数据量过大的问题
  • 避免IO竞争并减少锁表的概率

水平分库 和 优势

水平分库:把同一个表的数据按照一定规则拆分到不同的数据库中,不同的数据库可以放到不同的服务器上。

水平分库的优势:

  • 解决了单库大数据量的瓶颈问题
  • IO冲突减少,锁的竞争减少,某个数据库出现问题不影响其他数据库(可用性),提高了系统的稳定性和可用性

水平拆分的缺点:

(分表、分库)

  • 分片事务一致性难以解决

  • 跨节点JOIN性能差,逻辑会变得复杂

  • 数据扩展难度大,不易维护

在系统设计时应根据业务耦合来确定垂直分库和垂直分表的方案,在数据访问压力不是特别大时应考虑缓存、读写分离等方法,若数据量很大,或持续增长可考虑水平分库分表,水平拆分所涉及的逻辑比较复杂,常见的方案有客户端架构和恶代理架构。

  • 应该 去掉 恶 字

分库分表后,ID键如何处理?***

分库分表后不能每个表的ID都是从1开始,所以需要一个全局ID,设置全局ID主要有以下几种方法:

UUID:

优点:本地生成ID,不需要远程调用;全局唯一不重复。

缺点:占用空间大,不适合作为索引。

数据库自增ID:在分库分表表后使用数据库自增ID,需要一个专门用于生成主键的库,每次服务接收到请求,先向这个库中插入一条没有意义的数据,获取一个数据库自增的ID,利用这个ID去分库分表中写数据。

优点:简单易实现。

缺点:在高并发下存在瓶颈。系统结构如下图(图片来源于网络)

img

  • Redis生成ID:
    • 优点:不依赖数据库,性能比较好。
    • 缺点:引入新的组件会使得系统复杂度增加
  • Twitter的snowflake算法:是一个64位的long型的ID,其中有1bit是不用的,41bit作为毫秒数,10bit作为工作机器ID,12bit作为序列号。
    • 1bit:第一个bit默认为0,因为二进制中第一个bit为1的话为负数,但是ID不能为负数.
    • 41bit:表示的是时间戳,单位是毫秒。
    • 10bit:记录工作机器ID,其中5个bit表示机房ID,5个bit表示机器ID。
    • 12bit:用来记录同一毫秒内产生的不同ID
  • 美团的Leaf分布式ID生成系统,美团点评分布式ID生成系统

MySQL的复制原理及流程?如何实现主从复制?***

MySQL复制:为保证主服务器和从服务器的数据一致性

  • 在向主服务器插入数据后,
  • 从服务器会自动将主服务器中修改的数据同步过来。

主从复制的原理:

主从复制主要有三个线程:binlog线程,I/O线程,SQL线程

  • 主服务器的 Binary log线程,放 Binary log
  • 子服务器 I/O线程读取,放到 中继日志 Relay log
  • SQL线程读取 Relay log

binlog线程:负责将主服务器上的数据更改写入到二进制日志(Binary log)中。
I/O线程:负责从主服务器上读取二进制日志(Binary log),并写入从服务器的中继日志(Relay log)中。
SQL线程:负责读取中继日志,解析出主服务器中已经执行的数据更改并在从服务器中重放
复制过程如下(图片来源于网络):

Relay
英
/ˈriːleɪ/
v.
(relay)转播;接替
n.
(relay) 继电器;接替,接替人员;驿马

img

  1. Master在每个事务更新数据完成之前,将操作记录写入到binlog中
  2. Slave从库连接Master主库,并且Master有多少个Slave就会创建多少个binlog dump线程。当Master节点的binlog发生变化时,binlog dump会通知所有的Slave,并将相应的binlog发送给Slave。
  3. I/O线程接收到binlog内容后,将其写入到中继日志(Relay log)中
  4. SQL线程读取中继日志,并在从服务器中重放。
    这里补充一个通俗易懂的图。

img

  1. 主从复制的作用:
  • 高可用和故障转移
  • 负载均衡
  • 数据备份
  • 升级测试

了解读写分离嘛?***

读写分离 主要依赖于主从复制,主从复制为读写分离服务。

读写分离的优势:

  • 主服务器负责写,从服务器负责读,缓解了锁的竞争
  • 从服务器可以使用MyISAM,提升查询性能及节约系统开销
  • 增加冗余,提高可用性

转自牛客网
作者:路人zhang
链接:https://www.nowcoder.com/discuss/637486?source_id=profile_create_nctrack&channel=-1
来源:牛客网

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值