MySQL总结

1

参考

https://www.cnblogs.com/williamjie/p/11081592.html
https://blog.csdn.net/cheidou123/article/details/91442955

一条SQL查询语句的执行

MySQL 可以分为Server 层和存储引擎层两部分

  • Server层 Server 层包括连接器、查询缓存、分析器、优化器、执行器
    等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视
    图,以及所有的内置函数(如日期、时间、数学和加密函数等)
  • 存储引擎 负责数据的存储和提取。其架构模式是插件式的,支持InnoDB
    、MyISAM、Memory 等多个存储引擎

执行流程如下

  1. 建立连接 客户端通过连接器与MySQL服务器建立连接
  2. 查询缓存 先查询数据库缓存是否存在(之前执行过相同条件的SQL查询
    ),如果有就直接返回缓存中的数据,如果语句不在查询缓存中,就会继续
    后面的执行阶段。执行完成后执行结果会被存入查询缓存中。以 key-value
    对的形式存储
  3. 分析器进行词法分析和语法分析 首先进行词法分析,识别出里面的字符
    串分别是什么,代表什么,也就是识别表名和列名。然后进行语法分析,判
    断你输入的这个SQL 语句是否满足MySQL 语法,也就是检查语句中的关键
    词,表,字段是否存在
  4. 优化器 表里面有多个索引的时候,决定使用哪个索引;或者在一个语句
    有多表关联(join)的时候,决定各个表的连接顺序
    1
    2
    3
    4
    5
    6
    7
    /*
    既可以先从表 t1 里面取出 c=10 的记录的 ID 值,再根据 ID 值关联
    到表 t2,再判断 t2 里面 d 的值是否等于 20
    也可以先从表 t2 里面取出 d=20 的记录的 ID 值,再根据 ID 值关联到
    t1,再判断 t1 里面 c 的值是否等于 10
    */
    select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
  5. 执行器 执行器就会根据表的引擎定义,去使用这个引擎提供的接口,直
    到查询出满足条件的所有数据,对于有索引的表,执行的逻辑也差不多。第
    一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下
    一行”这个接口。数据库的慢查询日志中看到一个rows_examined 的字段
    ,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用
    引擎获取数据行的时候累加的。在有些场景下,执行器调用一次,在引擎
    内部则扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全
    相同的

长连接和短连接

长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接。短
连接则是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一
个。有些时候MySQL 占用内存涨得特别快,这是因为MySQL 在执行过程中临
时使用的内存是管理在连接对象里面的。这些资源会在连接断开的时候才释
放。所以如果长连接累积下来,可能导致内存占用太大。考虑以下两种方案

  1. 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存
    的大查询后,断开连接,之后要查询再重连
  2. 每次执行一个比较大的操作后,通过执行 mysql_reset_connection
    来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将
    连接恢复到刚刚创建完时的状态

查询缓存的利弊

  1. 如果查询命中缓存,MySQL 不需要执行后面的复杂操作,就可以直接返回
    结果,这个效率会很高
  2. 查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询
    缓存都会被清空,对于更新压力大的数据库来说,查询缓存的命中率会非常
    低,MySQL 8.0 版本已不支持

权限验证时机

连接器是账号权限校验,分析器是库权限验证,执行器是语句在表中权限验证

一条SQL更新语句的执行

DML和DDL

  1. DML 数据操作语言-数据库的基本操作,SQL中处理数据等操作统称为数
    据操纵语言,简而言之就是实现了基本的“增删改查”操作。包括的关键字有
    :select、update、delete、insert、merge
  2. DDL 数据定义语言-用于定义和管理 SQL 数据库中的所有对象的语言,对
    数据库中的某些对象(例如,database,table)进行管理。包括的关键字有:
    create、alter、drop、truncate、comment、grant、revoke

redo log和binlog 的区别

  1. 产生位置不同 redo log 是InnoDB 引擎特有的;binlog 是MySQL 的
    Server 层实现的,所有引擎都可以使用
  2. 内容形式不同 redo log 是物理日志,记录的是“在某个数据页上做了什
    么修改”;binlog 逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2
    这一行的c 字段加 1 ”
  3. redo log 是循环写的,空间固定会用完;binlog 是可以追加写入的。
    “追加写”是指binlog 文件写到一定大小后会切换到下一个,并不会覆盖以
    前的日志
  4. 写入磁盘的时间不同 binlog 只在事务提交完成后进行一次写入,而
    InnoDB存储引擎的重做日志在事务进行中不断地被写入,也就是说并不是
    按照事务提交的顺序进行写入。而且二进制日志只包含对应事务的一个日
    志,重做日志包含每个事务的多个物理操作日志s
  5. 恢复数据时,redolog用于恢复主机故障时的未更新的物理数据,binlog
    用于备份操作。每个阶段的log操作都是记录在磁盘的,在恢复数据时redolog
    状态为commit则说明binlog也成功,直接恢复数据;如果redolog是prepare
    ,则需要查询对应的binlog事务是否成功,决定是回滚还是执行

更新流程

  1. 执行器先找引擎取数据。如果这一行所在的数据页本来就在内存中,就直
    接返回给执行器;否则,需要先从磁盘读入内存,然后再返回
  2. 执行器拿到引擎给的行数据,把这个值加上1,比如原来是N,现在就是
    N+1,得到新的一行数据,再调用引擎接口写入这行新数据
  3. 引擎将这行新数据更新到内存中,同时将这个更新操作记录到 redo log
    里面,此时 redo log 处于 prepare 状态。然后告知执行器执行完成了,
    随时可以提交事务
  4. 执行器生成这个操作的 binlog,并把 binlog 写入磁盘
  5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log 改成提交
    状态,更新完成

redo log

脏页和干净页

当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。
内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净
页”

刷新脏页的时机

  1. redo log满了
  2. 需要新的内存页,而内存不够用的时候,就要淘汰一些数据页。内存满时
    不刷脏页,而是将其直接覆盖掉。那下次请求磁盘中的干净页到内存时,需
    要做额外判定redo log中是否有对该页的修改
  3. mysql空闲的时候
  4. mysql正常关闭的时候

刷盘速度影响因素

  1. 脏页比例
  2. redo log 写盘速度

binlog

事务隔离

数据库事务

事务指的是满足 ACID 特性的一组操作,要么都执行,要么都不执行,事务
会把数据库从一种一致性状态转换到另一种一致性状态

事务的ACID

  1. 原子性 Atomicity 原子性是指事务是一个不可分割的工作单位,事务
    中的操作要么全部成功,要么全部失败。事务在执行过程中出现错误时,就
    会回滚到事务开始前的状态,好像事务从来没有执行过一样,通过回滚日
    志实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些
    修改操作即可
  2. 一致性 Consistency 事务必须使数据库从一个一致性状态变换到另外
    一个一致性状态。一致性是通过原子性、隔离性和持久性一起实现的。一致
    性是事务的根本追求,数据库系统通过并发控制技术和日志恢复技术来避
    免错误情况
  3. 隔离性 Isolation 事务的隔离性是多个用户并发访问数据库时,数据
    库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并
    发事务之间要相互隔离,通过锁和mvvc实现
  4. 持久性 Durability 持久性是指一个事务一旦被提交,它对数据库中
    数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任
    何影响,系统发生崩溃可以用重做日志(Redo Log)进行恢复,从而实
    现持久性。与回滚日志记录数据的逻辑修改不同,重做日志记录的是数
    据页的物理修改

事务常见问题

  1. 脏读 脏读指一个事务读取了另外一个事务未提交的数据
  2. 不可重复读 一个事务读取数据,多次读取结果不同。与脏读的区别在
    于脏读是读取前一事务未提交的脏数据,而不可重复读是读取前一事务
    已提交的数据
  3. 幻读 一个事务读取数据,另一个事务插入新的数据,前后读取的记录数
    量不一致。
    幻读本质上也属于不可重复读的情况,T1读取某个范围的数据,T2在这个范
    围内插入新的数据,T1再次读取这个范围的数据,此时读取的结果和和第一
    次读取的结果不同。根本原因是行锁只能锁住行,但是新插入记录这个动作
    ,要更新的是记录之间的“间隙”。
    幻读与不可重复读的差别在于不可重复读对应的是update,可以通过可重复
    读防止别的事务update数据,但是幻读对应的是insert操作,所以可重复
    读无法阻止幻读,需要通过mvvc+next-key lock实现

事务的隔离级别

读未提交 读已提交 可重复读 可串行化

  1. read uncommitted 事务中的修改,即使没有提交,对其它事务也是可
    见的,没有解决脏读、不可重复读和幻读。本质是该隔离级别下非锁定读读
    取的都是最新的行数据,并没有使用MVVC机制
  2. read committed 一个事务只能读取已经提交的事务所做的修改。换句
    话说,一个事务所做的修改在提交之前对其它事务是不可见的。解决了脏读
    ,没有解决不可重复读和幻读
  3. repeatable read 保证在同一个事务中多次读取同一数据的结果是一
    样的,解决了脏读和不可重复读,没有解决幻读
  4. serializable 强制事务串行执行,这样多个事务互不干扰,不会出现
    并发一致性问题。该隔离级别需要加锁实现,因为要使用加锁机制保证同一
    时间只有一个事务执行,也就是保证事务串行执行,解决所有读问题

为什么不推荐使用长事务

长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访
问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能
用到的回滚记录都必须保留,这就会导致大量占用存储空间,长事务还
占用锁资源

事务的启动

  1. 显式启动事务语句 begin 或start transaction。配套的提交语句是
    commit,回滚语句是rollback
  2. set autocommit=0 这个命令会将这个线程的自动提交关掉。意味着如
    果你只执行一个select 语句,这个事务就启动了而且并不会自动提交。这
    个事务持续存在直到你主动执行commit 或rollback 语句或者断开连接
  3. begin/start transaction 命令并不是一个事务的起点,在执行到它
    们之后的第一个操作InnoDB 表的语句,事务才真正启动

如何解决幻读

Mysql 默认采用的 REPEATABLE_READ 隔离级别,Oracle 默认采用的
READ_COMMITTED隔离级别。事务隔离机制的实现基于锁机制和并发调度
。其中并发调度使用的是MVVC(多版本并发控制),通过保存修改的旧
版本信息来支持并发一致性读和回滚等特性。在读已提交和可重复读两
种隔离级别下用到了MVVC。
可重复读隔离级别下没有解决幻读,通过MVCC + Next-Key Locks 可以
解决幻读问题。MVVC解决的是普通读(快照读)的幻读,next-key locks
解决的是当前读情况下的幻读

快照读和当前读的区别

  1. 快照读 像不加锁的select操作就是快照读,即不加锁的非阻塞读,快
    照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前
    读,之所以出现快照读的情况,是基于提高并发性能的考虑,快照读的实
    现是基于多版本并发控制,即MVCC,可以认为MVCC是行锁的一个变种,但
    它在很多情况下,避免了加锁操作,降低了开销,既然是基于多版本,即
    快照读可能读到的并不一定是数据的最新版本,而有可能是之前的历史版
  2. 当前读 像select lock in share mode(共享锁), select for
    update;update, insert ,delete(排他锁)这些操作都是一种当前
    读,为什么叫当前读?就是它读取的是记录的最新版本,读取时还要
    保证其他并发事务不能修改当前记录,会对读取的记录进行加锁

什么是版本号

  • 系统版本号 SYS_ID:是一个递增的数字,每开始一个新的事务,系统版
    本号就会自动递增
  • 事务版本号 TRX_ID :事务开始时的系统版本号

MVVC的原理

同一条记录在系统中可以存在多个版本,每次事务更新数据的时候,都会生
成一个新的数据版本,同时旧的数据版本要保留,并且在新的数据版本中,
能够有信息可以直接拿到它。一个事务启动的时候,能够看到所有已经提交
的事务结果。但是之后,这个事务执行期间,其他事务的更新对它不可见

  1. 3个隐式字段
  2. undo日志
  3. Read View

实现原理主要是依赖记录中的3个隐式字段,undo日志和 Read View 来实现
的,主要实现思想是通过数据多版本来做到读写分离,从而实现不加锁而做到
读写并行。 写操作更新最新的版本快照,而读操作去读旧版本快照,没有互斥
关系。在 MVCC 中事务的修改操作(DELETE、INSERT、UPDATE)会为数据行新
增一个版本快照。MVCC 规定只能读取已经提交的快照

隐式字段的作用

三个隐藏的列分别是最近修改(修改/插入)事务ID、回滚指针和隐含的自增ID
(隐藏主键)

  1. 事务ID 记录创建这条记录/最后一次修改该记录的事务ID
  2. 回滚指针 指向这条记录的上一个版本
  3. 如果数据表没有主键,InnoDB会自动以DB_ROW_ID产生一个聚簇索引

undo日志和Read review的作用

  1. undo log 记录某行数据的多个版本的数据,MVCC 的多版本指的是多个
    版本的快照,快照存储在 Undo 日志中,该日志通过回滚指针 ROLL_PTR把
    一个数据行的所有快照连接起来,不同事务或者相同事务的对同一记录的修
    改,会导致该记录的undo log成为一条记录版本线性表既链表,undo log
    的链首就是最新的旧记录,链尾就是最早的旧记录
  2. read review 用来判断当前版本数据的可见性

系统会判断当没有事务需要用到这些回滚日志的时候,回滚日志会被删除

read review的作用

  1. Read View就是事务进行快照读操作的时候生产的读视图(Read View),
    在该事务执行的快照读的那一刻,会生成数据库系统当前的一个快照,记录
    并维护系统当前活跃事务的ID(当每个事务开启时,都会被分配一个ID, 这
    个ID是递增的,所以最新的事务,ID值越大)。Read View主要是用来做可
    见性判断的,即当我们某个事务执行快照读的时候,对该记录创建一个
    Read View读视图,把它比作条件用来判断当前事务能够看到哪个版本
    的数据,既可能是当前最新的数据,也有可能是该行记录的undo log
    里面的某个版本的数据

提交读和可重复读读取的快照不一样

  • 提交读:如果 TRX_ID 在 TRX_IDs 列表中,表示该数据行快照对应的事
    务还未提交,则该快照不可使用。否则表示已经提交,可以使用
  • 可重复读:都不可以使用。因为如果可以使用的话,那么其它事务也可以读
    到这个数据行快照并进行修改,那么当前事务再去读这个数据行得到的值就
    会发生改变,也就是出现了不可重复读问题

RC,RR级别下的InnoDB快照读的区别

  1. 在RR级别下的某个事务的对某条记录的第一次快照读会创建一个快照及
    Read View ,将当前系统活跃的其他事务记录起来,此后在调用快照读的
    时候,还是使用的是同一个Read View ,所以只要当前事务在其他事务提
    交更新之前使用过快照读,那么之后的快照读使用的都是同一个Read
    View,所以对之后的修改不可见
  2. 即RR级别下,快照读生成Read View 时,Read View会记录此时所有其
    他活动事务的快照,这些事务的修改对于当前事务都是不可见的。而早于
    Read View创建的事务所做的修改均是可见
  3. 而在RC级别下的,事务中,每次快照读都会新生成一个快照和Read
    View,这就是我们在RC级别下的事务中可以看到别的事务提交的更新的原因

总之在RC隔离级别下,是每个快照读都会生成并获取最新的Read View,而在RR
隔离级别下,则是同一个事务中的第一个快照读才会创建Read View, 之后的快
照读获取的都是同一个Read View

MVCC 的好处

主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有
读写冲突时,也能做到不加锁,非阻塞并发读。解决读-写冲突的无锁并发控制
,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事
务时间戳关联,读操作只读该事务开始前的数据库的快照。 所以MVCC可以为
数据库解决以下问题

  • 在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用
    阻塞读操作,提高了数据库并发读写的性能
  • 同时还可以解决脏读,幻读,不可重复读等事务隔离问题,但不能解决更新
    丢失问题

MySQL如何实现事务

MySQL事务的ACID,一致性是最终目的。
保证一致性的措施有:

  • A原子性:靠undo log来保证(异常或执行失败后进行回滚)
  • D持久性:靠redo log来保证(保证当MySQL宕机或停电后,可以通过redo
    log 最终将数据保存至磁盘中)
  • I隔离性:事务间的读写靠MySQL的锁机制来保证隔离,事务间的写操作靠
    MVCC机制(快照读、当前读)来保证隔离性
  • C一致性:事务的最终目的,即需要数据库层面保证,又需要应用层面进行
    保证,并且MySQL底层通过两阶段提交事务保证了事务持久化时的一致性

索引

索引是一种数据结构。数据库索引,是数据库管理系统中一个排序的数据结构,
以协助快速查询、更新数据库表中数据

索引模型

哈希索引为什么不行

必须要具备好的hash 算法,如果算法不合适会导致数据散列不均匀,造
成很大空间的浪费,如果某些链表过长则需要顺序遍历,效率太低。不支
持范围查询,因为不是有序的所以哈希索引做区间查询的速度是很慢的。
适用于只有等值查询的场景。Memory存储引擎使用哈希索引,innodb支
持自适应哈希索引

常见搜索树为什么不行

  1. 二叉树为什么不行 二叉树本身是无序的,一般使用二分查找树BST,左
    子树小于根节点,右子树大于根节点,这样这棵树就有序了。如果是递增插
    入或递减插入那么这棵树就退化成一个链表,那么查询复杂度又变成O(n)
    ,所以接下来的优化应该是保证这棵树的平衡
  2. 平衡二叉树AVL为什么不行 AVL树最短子树和最长子树高度差不能超过1
    ,为了保证平衡在插入数据的时候必须进行旋转,通过插入性能的损失来弥
    补查询性能的提升。如果读写请求一样多那么AVL树就不合适,优化思路就
    是在插入情况多的时候提升性能
  3. 红黑树为什么不行 红黑树的最长子树只要不超过最短子树的两倍即可
    ,查询性能和插入性能近似相同。但是随着数据的插入,树的深度会变深
    ,依然会影响性能。优化思路就是减少树的深度,注意这几个树都是每个
    节点最多两个分支,把有序二叉树变为有序多叉树,那么每个节点至少
    要有两个记录

为什么使用N叉树

  1. 索引不止存在内存中,还要写到磁盘上。在数据库中,不论读一行还是
    读多行,都是将这些行所在的页进行加载。也就是说存储空间的基本单位
    是页,一个页就是一棵树B+树的节点,数据库I/O操作的最小单位是页,
    与数据库相关的内容都会存储在页的结构里,访问一个节点相当于一次
    I/O操作,所以越快能找到节点,查找性能越好。B+树的特点就是够矮
    够胖,能有效地减少访问节点次数从而提高性能
  2. 因为二叉树树高过高,每次查询都需要访问过多节点,即访问数据块过
    多,而从磁盘随机读取数据块过于耗时。B+树的特点就是够矮够胖,能有效
    地减少访问节点次数从而提高性能

B树和B+树的区别

  1. B树为什么不行 每个节点都存储key和data和子节点指针,一个节点可
    以有多个key,所有节点组成一棵B树,假设1条记录占用1KB,一个节点占
    用一个磁盘块的空间,那么一个节点可以有16条记录,三层的B树最多能
    够保存4096条记录,随着深度的增大保存的数据越多,IO操作次数也会
    越多,优化的思路依然是减少深度,B树占用的大部分空间都是因为数
    据占用
  2. B+树为什么行 B+树只有叶子节点才会存储数据,非叶子节点不存储数
    据, 那么就要根据key和子节点占用的空间决定,占用的空间越小每个磁
    盘块能够表示的范围就越大,所以在创建索引的时候要注意key 占用的空
    间,如果使用varchar 大于4个字节那么就用int 作为索引,否则就使用
    varchar,key 越小就能存储越多的数据,注意叶子节点构成一个双向循
    环链表,节点的度是根据key和指针的大小来计算的。key值最好能够自增
    ,这样可以避免叶子节点和非叶子节点的分裂。B+树有两种数据访问的方
    式,一种是从根节点开始查找,另一种是从叶子节点开始顺序查找,无
    法使用索引的时候就可以采用第二种方式

存储结构

  1. 单位:表>段>区>页>行
  2. 在数据库中, 不论读一行,还是读多行,都是将这些行所在的页进行
    加载。也就是说存储空间的基本单位是页
  3. 一个页就是一棵树B+树的节点,数据库I/O操作的最小单位是页,与数
    据库相关的内容都会存储在页的结构里
  4. 数据库访问数据要通过页,一个页就是一个B+树节点,访问一个节点相
    当于一次I/O操作,所以越快能找到节点,查找性能越好
  5. 一个页的大小是16K,一个整数(bigint)字段索引的长度为 8B,另外
    每个索引还跟着6B 的指向其子树的指针;所以16K/14B ≈ 1170。每个节点
    大约可以有1200个分叉,这棵树高是4 的时候,就可以存1200 的3 次方个
    值,这已经17 亿了

InnoDB 的索引模型

在InnoDB 中,表都是根据主键顺序以索引的形式存放的,这种存储方式的
表称为索引组织表。在InnoDB 中,每一张表其实就是多个B+ 树,即一个
主键索引树和多个非主键索引树。如果不使用索引进行查询,则从主索引
B+ 树的叶子节点进行遍历

  1. 主键索引 主键索引的叶子节点存的是整行数据
  2. 非主键索引 非主键索引的叶子节点内容是主键的值

回表

先根据普通索引查询到聚集索引的key值,然后根据key值在聚集索引中查询
到对应的行记录,这就是回表

为什么自增列作为主键

  1. 数据记录本身被存于主索引(一颗B+Tree)的叶子节点上。这就要求同
    一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺
    序存放,因此每当有一条新的记录插入时,MySQL会根据其主键将其插入
    适当的节点和位置,如果页面达到装载因子,则开辟一个新的页(节点)
  2. 如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当
    前索引节点的后续位置,当一页写满,就会自动开辟一个新的页
  3. 如果使用非自增主键,由于每次插入主键的值近似于随机,因此每次新
    纪录都要被插到现有索引页得中间某个位置,不得不为了将新记录插到合
    适位置而移动数据,频繁的移动、分页操作造成了大量的碎片

业务字段不适合做自增主键

  1. 业务字段不一定是递增的,有可能会造成主键索引的页分裂,导致性能
    不稳定
  2. 二级索引存储的值是主键,如果使用业务字段占用大小不好控制,如果
    业务字段过长可能会导致二级索引占用空间过大,利用率不高

索引的优缺点

  1. 优点
  • 可以大大加快数据的检索速度,这也是创建索引的最主要的原因
  • 通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能
  1. 缺点如下
  • 时间方面:创建索引和维护索引要耗费时间,具体地,当对表中的数据进行
    增加、删除和修改的时候,索引也要动态的维护,会降低增/改/删的执行效率
  • 空间方面:索引需要占物理空间

聚集索引和非聚集索引的区别

  1. Innodb存储引擎插入数据时必须要将数据跟某一个索引绑定在一起,这
    个索引就是聚集索引。一个表中有多个索引列,但是数据只有一份,其他索
    引没有与数据的值绑定在一起,这些索引就是非聚集索引
  2. Innodb中存在聚集索引和非聚集索引,MyISAM中只有非聚集索引
  3. 正文内容按照一个特定维度排序存储,这个特定的维度就是聚集索引,表
    中只能由一个,一般是表中的主键索引,如果表中没有显示指定主键,则会
    选择表中的第一个不允许为NULL的唯一索引,如果还是没有的话,就采用
    Innodb存储引擎为每行数据内置的6字节ROWID作为聚集索引。聚集索引
    性能在精确查找和范围查找上面效果要好
  4. 非聚集索引索引项顺序存储,但索引项对应的内容却是随机存储的
  5. 聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物
    理存储并不连续,聚集索引是一种索引组织形式,索引的键值逻辑顺序决定
    了表数据行的物理存储顺序,按照聚集索引排序
  6. 非聚集索引物理存储不按照索引排序,非聚集索引则就是普通索引了,仅
    仅只是对数据列创建相应的索引,不影响整个表的物理存储顺序
  7. 聚集索引插入数据时速度要慢(时间花费在“物理存储的排序”上,也就是首
    先要找到位置然后插入),查询数据比非聚集数据的速度快

索引覆盖

在这个查询里面,索引k 已经覆盖了我们的查询需求,我们称为覆盖索引。
从索引的叶子节点中获取到全量查询列,不需要从聚集索引中查任何数据,
不需要回表

1
2
3
4
5
6
select id,name from table where name='zhangsan'
从索引的叶子节点中获取到全量查询列的过程叫做索引覆盖
explain的输出结果Extra字段为Using index时,能够触发索引覆盖。
select id,name,sex ... where name='shenjian';
单列索升级为联合索引(name, sex)后,索引叶子节点存储了主键id,name,sex,
都能够命中索引覆盖,无需回表。

联合索引

对查询语句中多个常用字段建立索引,尽量减少同一个表上的索引数量,减少
因为数据更新带来的索引更新成本,同时还可以减少因为索引所消耗的存储空
间。在联合索引中,如果想要命中索引,需要按照建立索引时的字段顺序挨个
使用,否则无法命中索引

最左前缀匹配原则

最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查
询(>、<、between、like)就会停止匹配

1
2
3
4
5
6
7
8
9
id name age gender id是主键,name和age是组合索引
select * from stu where name='ff' and age=11
符合最左匹配原则
select * from stu where name='ff'
符合最左匹配原则
select * from stu where age=11
不符合最左匹配原则
select * from stu where age=11 and name='ff'
符合最左匹配原则,优化器会改变列的顺序,选择合适的顺序执行

如果既有联合查询,又有基于 a、b 各自的查询,查询条件里面只有b 的
语句,是无法使用 (a,b) 这个联合索引的,这时候你不得不维护另外一
个索引,也就是说你需要同时维护 (a,b)、(b) 这两个索引。

索引下推

  1. 在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条
    件的记录,减少回表次数
  2. 不使用索引条件下推优化时存储引擎通过索引检索到数据,然后返回给
    MySQL服务器,服务器然后判断数据是否符合条件
  3. 当使用索引条件下推优化时,如果存在某些被索引的列的判断条件时,
    MySQL服务器将这一部分判断条件传递给存储引擎,然后由存储引擎通过
    判断索引是否符合MySQL服务器传递的条件,只有当索引符合条件时才会
    将数据检索出来返回给MySQL服务器。索引条件下推优化可以减少存储引
    擎查询基础表的次数,也可以减少MySQL服务器从存储引擎接收数据的
    次数,减少回表次数

这个优化技术关键的操作就是将与索引相关的条件由MySQL服务器向下传递至存
储引擎,由此减少IO次数。MySQL服务器到存储引擎是向下,传递的是与索引列
相关的查询条件。索引下推优化技术其实就是充分利用了索引中的数据,尽量在
查询出整行数据之前过滤掉无效的数据,只适用于二级索引。

1
2
3
4
5
6
7
SELECT * FROM person  WHERE `name` = "1" AND `address` LIKE "%222" 
and first_name LIKE "%222";
如果不使用索引条件下推优化的话,MySQL只能根据索引查询出name=1的所有行,然
后再依次比较是否符合全部条件。
当使用了索引条件下推优化技术后,可以通过索引中存储的数据判断当前索引对应的
数据是否符合条件,只有符合条件的数据才将整行数据查询出来。查看执行计划时发
现extra一栏中有Using index condition信息,说明使用了索引下推。

索引的优化方式有哪些?

联合索引、最左匹配原则、覆盖索引、索引下推

非聚簇索引一定会回表查询吗?

当查询使用聚簇索引时,在对应的叶子节点,可以获取到整行数据,因此不用再
次进行回表查询。非聚簇索引不一定,这涉及到查询语句所要求的字段是否全部
命中了索引,如果全部命中了索引,那么就不必再进行回表查询

索引有哪几种类型?

  1. 普通索引:最基本的索引,没有任何约束,允许为NULL值
    1
    2
    ALTER TABLE table_name ADD INDEX index_name (column);
    ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);
  2. 唯一索引:与普通索引类似,但具有唯一性约束,唯一索引数据列不能重复
    ,可以提高效率,也可以防重
    1
    2
    ALTER TABLE table_name ADD UNIQUE (column);
    ALTER TABLE table_name ADD UNIQUE (column1,column2);
  3. 主键索引:特殊的唯一索引,不允许有空值
  4. 复合索引:将多个列组合在一起创建索引,可以覆盖多个列
  5. 外键索引:只有InnoDB类型的表才可以使用外键索引,保证数据的一致
    性、完整性和实现级联操作
  6. 全文索引:MySQL 自带的全文索引只能用于 InnoDB、MyISAM,是目前
    搜索引擎使用的一种关键技术
    1
    ALTER TABLE table_name ADD FULLTEXT (column);

索引创建方式有哪些?

  1. 表建立时就进行约束定义
  2. 使用alter table创建约束,Unique Key还可以通过create unique
    index 来创建

如何创建主键?

在InnoDB存储引擎中,表都是根据主键顺序组织存放的,这种存储方式
的表称为索引组织表。每张表都有一个主键

  • 首先判断表中是否有非空的唯一索引,如果有则该列为主键。当有多个
    非空唯一索引时,将选择建表时第一个定义的非空唯一索引为主键
  • 如果不符上述条件则InnoDB自动创建一个6字节大小的指针

约束和索引的区别

约束是一个逻辑的概念,用来保证数据的完整性,而索引是一个数据结构,
既有逻辑的概念,在数据库中还代表物理存储的方式

  1. key 是数据库的逻辑结构,它包含两层意义和作用,一是约束(偏重于约
    束和规范数据库的结构完整性),二是索引(辅助查询用的)。包括primary
    key, unique key, foreign key 等
  2. index是数据库的物理结构,它只是辅助查询的,它创建时会在另外的表
    空间(mysql中的innodb表空间)以一个类似目录的结构存储。索引要分类
    的话,分为前缀索引、全文本索引等

varchar和char的区别?

varchar会动态分配长度,char指定长度是固定的

MyISAM和InnoDB实现BTree索引方式的区别?

  1. MyISAM B+Tree叶节点的data域存放的是数据记录的地址,在索引检索
    的时候,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出
    其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被
    称为“非聚簇索引”。 索引文件和数据文件是分离的
  2. InnoDB InnoDB 的 B+Tree 索引分为聚集索引和非聚集索引。一张表一
    定包含一个聚集索引构成的B+ 树以及若干辅助索引的构成的B+ 树

B树和B+树的区别是什么?

  1. 在B树中,你可以将键和值存放在内部节点和叶子节点,但在B+树中,内
    部节点都是键没有值,叶子节点同时存放键和值
  2. B+树的叶子节点有一条链相连,而B树的叶子节点各自独立
  3. B树可以在内部节点同时存储键和值,因此,把频繁访问的数据放在靠近
    根节点的地方将会大大提高热点数据的查询效率。这种特性使得B树在特定数
    据重复多次查询的场景中更加高效
  4. 由于B+树的内部节点只存放键,不存放值,因此一次读取可以在内存页中
    获取更多的键,有利于更快地缩小查找范围。 B+树的叶节点由一条链相连,
    因此当需要进行一次全数据遍历的时候,B+树只需要使用O(logN)时间找到
    最小的一个节点,然后通过链进行O(N)的顺序遍历即可。而B树则需要对树
    的每一层进行遍历,这会需要更多的内存置换次数,因此也就需要花费更
    多的时间

Hash索引和B+树的区别是什么?

  1. hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取
    到相应的键值,之后进行回表查询获得实际数据。B+树底层实现是多路平衡
    查找树。对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得
    所查键值,然后根据查询判断是否需要回表查询数据,从根节点到每个叶
    子节点的高度差值不超过1,而且同层级的节点间有指针相互链接,是有
    序的
  2. hash索引进行等值查询更快(前提是没有大量重复键值),但是却无法
    进行范围查询
  3. 因为在hash索引中经过hash函数建立索引之后,索引的顺序与原顺序无
    法保持一致,不能支持范围查询。而B+树的的所有节点皆遵循(左节点小于
    父节点,右节点大于父节点,多叉树也类似),天然支持范围
  4. hash索引不支持使用索引进行排序,原理同上
  5. hash索引不支持模糊查询以及多列索引的最左前缀匹配。原理也是因为
    hash函数的不可预测。AAAA和AAAAB的索引没有相关性
  6. hash索引任何时候都避免不了回表查询数据,而B+树在符合某些条件(
    聚簇索引,覆盖索引等)的时候可以只通过索引完成查询
  7. hash索引虽然在等值查询上较快,但是不稳定。性能不可预测,当某个
    键值存在大量重复的时候,发生hash碰撞,此时效率可能极差。而B+树的
    查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高
    度较低

索引的基本原理是什么?

索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行
查询时遍历整张表。索引的原理很简单,就是把无序的数据变成有序的查询

  1. 把创建了索引的列的内容进行排序
  2. 对排序结果生成倒排表
  3. 在倒排表内容上拼上数据地址链
  4. 在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据

使用索引查询一定能提高查询的性能吗?

索引需要空间来存储,也需要定期维护,每当有记录在表中增减或索引列被修改
时,索引本身也会被修改。 这意味着每条记录的INSERT,DELETE,UPDATE将
为此多付出4,5 次的磁盘I/O。 因为索引需要额外的存储空间和处理,那些
不必要的索引反而会使查询反应时间变慢。使用索引查询不一定能提高查询
性能,索引范围查询(INDEX RANGE SCAN)适用于两种情况:

  • 基于一个范围的检索,一般查询返回结果集小于表中记录数的30%
  • 基于非唯一性索引的检索

什么是前缀索引

语法:index(field(10)),使用字段值的前10个字符建立索引,默认是使用
字段的全部内容建立索引。前提:前缀的标识度高。比如密码就适合建立前缀
索引,因为密码几乎各不相同。对于BLOB、TEXT或者很长的VARCHAR类型的
列,必须使用前缀索引,因为MySQL不允许索引这些列的完整长度

什么是最左前缀原则?

  1. 就是最左优先,在创建多列索引时,要根据业务需求,where子句中使用最
    频繁的一列放在最左边
  2. mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就停止匹配
    ,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的
    索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的
    顺序可以任意调整。=和in可以乱序,比如a = 1 and b = 2 and c = 3 建
    立(a,b,c)
  3. 索引可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式

数据库为什么使用B+树而不是B树?

  1. B树只适合随机检索,而B+树同时支持随机检索和顺序检索
  2. B+树空间利用率更高,可减少I/O 次数,磁盘读写代价更低。一般来说,
    索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形
    式存储的磁盘上。这样的话,索引查找过程中就要产生磁盘I/O 消耗。B+树
    的内部结点并没有指向关键字具体信息的指针,只是作为索引使用,其内
    部结点比B树小,盘块能容纳的结点中关键字数量更多,一次性读入内存
    中可以查找的关键字也就越多,相对的,IO 读写次数也就降低了。而IO
    读写次数是影响索引检索效率的最大因素
  3. B+树的查询效率更加稳定。B树搜索有可能会在非叶子结点结束,越靠近根
    节点的记录查找时间越短,只要找到关键字即可确定记录的存在,其性能等
    价于在关键字全集内做一次二分查找。而在B+树中,顺序检索比较明显,随
    机检索时,任何关键字的查找都必须走一条从根节点到叶节点的路,所有
    关键字的查找路径长度相同,导致每一个关键字的查询效率相当
  4. B-树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。
    B+树的叶子节点使用指针顺序连接在一起,只要遍历叶子节点就可以实现整
    棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持
    这样的操作
  5. 增删文件(节点)时,效率更高。因为B+树的叶子节点包含所有关键字,并
    以有序的链表结构存储,这样可很好提高增删效率

什么时候索引会失效?

  1. 对于创建的多列索引(复合索引),不是使用的第一部分就不会使用索引
  2. 对于使用 like 查询, 查询如果是’%aaa’或’_aaa’ 不会使用索引,而
    ‘aaa%’’会使用到索引
  3. 如果条件中有 or, 有条件没有使用索引,即使其中有条件带索引也不会
    使用,换言之就是要求使用的所有字段,都必须单独使用时能使用索引
  4. 如果列类型是字符串,那么一定要在条件中使用引号引用起来,否则不使
    用索引
  5. 如果mysql认为全表扫描要比使用索引快,则不使用索引

锁的作用

处理并发问题。作为多用户共享的资源,当出现并发访问的时候,数据库
需要合理地控制资源的访问规则,而锁就是用来实现这些访问规则的重
要数据结构

按照锁的粒度分类

MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类

全局锁

对整个数据库实例加锁,当你需要让整个库处于只读状态的时候,可以使
用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的
增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提
交语句。全局锁的典型使用场景是,做全库逻辑备份

1
2
Flush tables with read lock
unlock tables

表级锁

MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁(MDL)

1
2
3
# lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象
lock tablesread/write
unlock tables
  1. 表锁 表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整
    张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使
    用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁
    )与表独占写锁(排他锁)
    特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最
    高,并发度最低
  2. MDL MDL 不需要显式使用,在访问一个表的时候会被自动加上。MDL 的
    作用是,保证读写的正确性。当对一个表做增删改查操作的时候,加MDL 读
    锁;当要对表做结构变更操作的时候,加MDL 写锁。也就是用来隔离DML和
    DDL的
  • 读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查
  • 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此
    如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开
    始执行
  • 申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦
    出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作
  • 事务中的 MDL 锁,在语句执行开始时申请,但是语句结束后并不会马上
    释放,而会等到整个事务提交后再释放

热点数据表

考虑一下这个场景。如果你要变更的表是一个热点表,虽然数据量不大,但是
上面的请求很频繁,而你不得不加个字段。办法如下:
在 alter table 语句里面设定等待时间,如果在这个指定的等待时间里面
能够拿到MDL 写锁最好,拿不到也不要阻塞后面的业务语句先放弃。之后开
发人员或者DBA 再通过重试命令重复这个过程

行锁

表示只针对当前操作的行进行加锁,在InnoDB 事务中,行锁是在需要的时
候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释
放。这个就是两阶段锁协议。如果你的事务中需要锁多个行,要把最可能
造成锁冲突、最可能影响并发度的锁尽量往后放

  1. 行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作
    的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但
    加锁的开销也最大。行级锁分为共享锁和排他锁。
    特点:开销大,加锁慢,会出现死锁,锁定粒度最小,发生锁冲突的概率最
    低,并发度也最高

死锁

当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程
释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。
当出现死锁以后,有两种策略:

  1. 一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数
    innodb_lock_wait_timeout 来设置,默认值是50s
  2. 另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某
    一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect
    设置为on,表示开启这个逻辑

删除一个表里面的前 10000 行数据

  1. 第一种,直接执行 delete from T limit 10000;
  2. 第二种,在一个连接中循环执行 20 次 delete from T limit 500;
  3. 第三种,在 20 个连接中同时执行 delete from T limit 500;

肯定选第二个。第一个事务太长,执行时间过长,如果是主备形式的,影响
数据同步的时间。 这么多数据如果回滚的话,那该是多痛苦的事情加锁的
时间过长,会造成锁超时的第三个,很明显有并发问题,如果产生循环等
待就是死锁了。其实可以把id利用起来,20个连接,每个都删500个id,
岂不更好

隔离级别与锁的关系是什么?

  • 在Read Uncommitted级别下,读取数据不需要加共享锁,这样就不会跟被修
    改的数据上的排他锁冲突,会读取最新数据
  • 在Read Committed级别下,读操作使用MVVC机制,读取最新的快照
  • 在Repeatable Read级别下,读操作使用MVVC机制,读取事务开始时读取的
    快照
  • SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并
    一直持有锁,直到事务完成

从锁的类别上分MySQL都有哪些锁呢?

  1. 共享锁: 又叫做读锁。 当用户要进行数据的读取时,对数据加上共享锁。
    共享锁可以同时加上多个
  2. 排他锁: 又叫做写锁。 当用户要进行数据的写入时,对数据加上排他锁。
    排他锁只可以加一个,他和其他的排他锁,共享锁都相斥

行锁锁的到底是什么?

表中有索引就索索引,否则就锁整个表。所以InnoDB的行锁就是靠锁住索引来
实现的

  1. 如果一个表没有索引 因为没有索引所以会自动创建一个主键,查询没有使
    用索引所以会全表扫描把每一个隐藏的聚集索引都锁住了
  2. 如果一个表有主键索引id,但是不通过索引来对数据进行加锁,那么锁的依
    然是整个表
  3. 表有主键索引id和非主键索引name,如果操作非主键索引name,那么先
    锁定非主键索引,然后锁定相关的主键索引。 在UPDATE、DELETE操作时,
    MySQL不仅锁定WHERE条件扫描过的所有索引记录,而且会锁定相邻的键
    值,即所谓的next-key locking
  4. 如果明确指定主键但是表中没有该值那么不会锁定任何数据,如果主键不
    明确的话会锁表,不明确就是没有使用等于而是使用像like等

InnoDB存储引擎的锁的算法有哪些?应用场景有哪些?

  1. Record lock:单个行记录上的锁
  2. Gap lock:间隙锁,锁定一个范围,不包括记录本身
  3. Next-key lock:record+gap 锁定一个范围,包含记录本身

不同的情况使用的锁也不一样

  1. innodb对于行的查询使用next-key lock
  2. Next-locking keying为了解决Phantom Problem幻读问题
  3. 当查询的索引含有唯一属性时,将next-key lock降级为record key
  4. Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导
    致幻读问题的产生有两种方式显式关闭gap锁:(除了外键约束和唯一性检查
    外,其余情况仅使用record lock)
  • 将事务隔离级别设置为RC
  • 将参数innodb_locks_unsafe_for_binlog设置为1

什么是死锁?怎么解决?

死锁是两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相
等待现象。解决死锁的方法如下

  1. 最简单的方式就是设置超时时间,当两个事务相互等待时当一个事务的等
    待时间超时其中一个事务就会回滚,另一个事务继续执行
  2. 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生
    概率
  3. 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过
    表级锁定来减少死锁产生的概率

乐观锁和悲观锁是什么?如何实现?

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数
据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观
并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技
术手段。无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为
是一种思想

  1. 悲观锁 这种借助数据库锁机制,在修改数据之前先锁定,再修改的方式
    被称之为悲观并发控制。总是假设最坏的情况,每次读取数据的时候都默认
    其他线程会更改数据,因此需要进行加锁操作。为数据处理的安全提供了保
    证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增
    加产生死锁的机会。另外还会降低并行性。实现场景如下
  • 传统的关系型数据库使用这种锁机制,比如行锁,表锁等,读锁,写锁等
    ,都是在做操作之前先上锁
  1. 乐观锁 乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交
    更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返
    回给用户错误的信息,让用户决定如何去做。乐观锁适用于读操作多的场景
    ,这样可以提高程序的吞吐量
  • CAS 实现:Java 中java.util.concurrent.atomic包下面的原子变量使
    用了乐观锁的一种 CAS 实现方式
  • 版本号控制:一般是在数据表中加上一个数据版本号 version字段,表示
    数据被修改的次数。当数据被修改时,version 值会+1。当线程A要更新数据
    值时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读
    取到的 version 值与当前数据库中的version值相等时才更新,否则重试
    更新操作,直到更新成功

CAS是什么?

乐观锁不需要借助数据库的锁机制,主要就是冲突检测和数据更新。
CAS 即比较并交换。是解决多线程并行情况下使用锁造成性能损耗的一种机制
,CAS 操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内
存位置的值(V)与预期原值(A)相匹配,那么处理器会自动将该位置值更新为
新值(B)。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令
之前返回该位置的值。CAS 有效地说明了“我认为位置(V)应该包含值(A)。
如果包含该值,则将新值(B)放到这个位置,否则,不要更改该位置,只
告诉我这个位置现在的值即可”。Java 中,sun.misc.Unsafe 类提供了
硬件级别的原子操作来实现这个 CAS。java.util.concurrent包下大量
的类都使用了这个 Unsafe.java 类的 CAS 操作

数据库乐观锁悲观锁具体是什么,写一个典型的乐观锁SQL语句?

  1. 悲观锁 select…for update / select … in share mode
  2. 乐观锁 我们为表添加一个字段 version,读取数据时将此版本号一同
    读出,之后更新时,对此版本号+1,同时将提交数据的version 与数据库
    中对应记录的当前version进行比对,如果提交的数据版本号大于数据库
    表当前版本号,则予以更新,否则认为是过期数据
    1
    2
    update table_name set num = #{num}
    , version = version + 1 where id = 1 and version = #{version}

MySQL三范式是什么?

  1. 第一范式 保证每列的原子性,数据库中所有表的字段值都是不可分解的原
    子值。第一范式是对关系模型的基本要求,不满足第一范式就不是关系数据库
  2. 第二范式 在第一范式的基础上,非主键列完全依赖于主键,而不能是依
    赖于主键的一部分。完全依赖是针对于属性组来说,当一组属性X能推出来Y
    的时候就说Y完全依赖于X。一组属性X中的其中一个或几个属性能推出Y就说
    Y部分依赖于X
  3. 第三范式 在第二范式的基础上,保证每列和主键都直接相关,也就是说
    决定某些字段值的必须是主键,第二范式与第三范式的区别在于第三范式消
    除了传递依赖

MySQL与Oracle的区别?

  1. MySQL是一个单进程多线程架构的数据库,Oracle是一个多进程数据库
  2. MySQL 数据库是插件式表存储引擎,存储引擎是基于表而不是基于数据库
    ,不同的表可以使用不同的存储引擎。而Oracle只有一种存储引擎,所有数据
    存储管理机制都是一样的

存储引擎是什么?

数据库存储引擎是数据库底层软件组织,不同的存储引擎提供不同的存储机
制,索引技巧、锁定水平等功能。通过show engines可以查看所有存储引擎

MySQL有几种存储引擎,有什么区别?

InnoDB MyISAM MEMROY ARCHIVE

  1. InnoDB 支持事务,实现了四个标准的隔离级别,默认级别是可重复读。
    对于数据的存储采用了聚集索引的方式,底层使用的是B+树。支持自适应哈
    希索引,行锁和表锁和外键和全文索引,支持在线热备份,适合大量insert
    delete update
  2. MyISAM 不支持事务、行级锁和外键,支持全文索引,索引和数据分开存
    储,只缓存索引文件,不缓存数据文件。适合大量select的情况,底层使用
    的也是B+树
  3. MEMORY 存储引擎将表中的数据存储在内存中,为查询和引用其他表数
    据提供快速访问。默认使用哈希索引,适用于存储临时数据的临时表
  4. ARCHIVE 只支持insert和select操作,提供了压缩功能,拥有高效的
    插入速度,但是这种引擎不支持索引,所以查询性能较差一些

如何选择存储引擎?

  1. 如果要提供提交、回滚和崩溃恢复能力的事务安全能力,并要求实现并发
    控制,InnoDB 是个很好的选择
  2. 如果数据表主要用来插入和查询记录,则MyISAM引擎能提供较高的处理
    效率,很适合管理邮件或Web服务器日志数据
  3. 如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,
    可以将数据保存在内存中的Memory 引擎。MySQL中使用该引擎作为临时表
    ,存放查询的中间结果
  4. 如果只有INSERT和SELECT操作,可以选择Archive引擎,Archive存
    储引擎支持高并发的插入操作,但是本身并不是事务安全的。Archive引
    擎非常适合存储归档数据,如历史记录和记录日志信息可以使用
    Archive引擎

InnoDB和MyISAM的比较

  1. 事务:InnoDB 是事务型的,可以使用 Commit 和 Rollback 语句
  2. 并发:MyISAM 只支持表级锁,而 InnoDB 还支持行级锁
  3. 外键:InnoDB 支持外键
  4. 备份:InnoDB 支持在线热备份,热备份是系统处于正常运转状态下的备份
  5. 崩溃恢复:MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复
    的速度也更慢
  6. 其它特性:MyISAM 支持压缩表和空间数据索引
  7. 索引结构 InnoDB索引和数据存储在一起,表结构保存在frm文件,数据和
    索引保存在ibd文件。MyISAM 索引和数据分开存储,只缓存索引文件,不缓
    存数据文件。表结构保存在frm文件,数据保存在MYD文件,索引保存在MYI
    文件

MyISAM索引与InnoDB索引的区别?

  1. InnoDB索引是聚簇索引,MyISAM索引是非聚簇索引
  2. InnoDB的主键索引的叶子节点存储着行数据,因此主键索引非常高效
  3. MyISAM索引的叶子节点存储的是行数据地址,需要再寻址一次才能得到数据
  4. InnoDB非主键索引的叶子节点存储的是主键和其他带索引的列数据,因此查
    询时做到覆盖索引会非常高效

InnoDB引擎的特性是什么?

  1. 插入缓冲(insert buffer) 对于非聚集索引的插入或更新,并不是每一
    次直接插入到索引页中,而是先判断缓冲池中是否有要插入的非聚集索引页
    ,如果有则直接插入,否则放入Insert Buffer 对象中,然后再以一定的
    频率和情况进行和辅助索引页子节点的merge
  2. 二次写(double write) 重做日志记录的是对页的物理操作,如果页本身
    已经损坏那么重做无意义,在重做之前用户需要一个页的副本,当写入失效
    时,先通过页的副本还原该页,然后重做
  3. 自适应哈希索引(ahi) 如果观察到建立索引可以带来速度上的提升,则建立
    哈希索引
  4. 预读(read ahead) 磁盘也会从这个位置开始顺序向后读取一定长度的数
    据放入内存,这个理论基础就是局部性原理:当一个数据被用到其附近的数
    据也通常会被马上使用。所以程序运行期间需要的数据通常应当比较集中。
    预读的长度一般为页的整数倍
  5. 异步IO 异步IO就是说用户在发送一个IO请求后能立即发送下一个IO请求,
    这就是AIO。AIO的另一个优势是可以进行IO merge操作
  6. 刷新邻接页 当刷新一脏页时,同时检测所在区(extent)的所有页,如果有
    脏页则一并刷新

SQL注入了解吗?

参考 https://www.cnblogs.com/myseries/p/10821372.html
所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求
的查询字符串,最终达到欺骗服务器执行恶意的SQL命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String sql = "select * from user_table where username=
' "+userName+" ' and password=' "+password+" '";

--当输入了上面的用户名和密码,上面的SQL语句变成:
SELECT * FROM user_table WHERE username=
'' or 1 = 1 -- and password='';

--分析SQL语句:
--条件后面username=”or 1=1 用户名等于 ” 或1=1 那么这个条件一定会成功;

/*然后后面加两个-,这意味着注释,它将后面的语句注释,让他们不起作用,这样
语句永远都--能正确执行,用户轻易骗过系统,获取合法身份。*/
--这还是比较温柔的,如果是执行
SELECT * FROM user_table WHERE
username='' ;DROP DATABASE (DB Name) --' and password=''
--其后果可想而知…

如何防止SQL注入?

  1. 检查变量数据类型和格式 只要是有固定格式的变量,在SQL语句执行前,
    应该严格按照固定格式去检查,确保变量是我们预想的格式,这样很大程度
    上可以避免SQL注入攻击
  2. 过滤特殊符号 对于无法确定固定格式的变量,一定要进行特殊符号过滤
    或转义处理
  3. 绑定变量,使用预编译语句 预编译语句就是将这类语句中的值用占位符
    替代,可以视为将sql语句模板化或者说参数化。预编译语句的优势在于归纳
    为:一次编译、多次运行,省去了解析优化等过程,此外预编译语句能防止
    sql注入。原理是采用了预编译的方法,先将SQL语句中可被客户端控制的
    参数集进行编译,生成对应的临时变量集,再使用对应的设置方法,为临
    时变量集里面的元素进行赋值,赋值函数setString(),会对传入的参数
    进行强制类型检查和安全检查,所以就避免了SQL注入的产生。参数化能防
    注入的原因在于,语句是语句,参数是参数,参数的值并不是语句的一部
    分,数据库只按语句的语义跑

mysql有关权限的表都有哪几个?

user,db,table_priv,columns_priv和host

  1. user权限表:记录允许连接到服务器的用户帐号信息,里面的权限是全
    局级的
  2. db权限表:记录各个帐号在各个数据库上的操作权限
  3. table_priv权限表:记录数据表级的操作权限
  4. columns_priv权限表:记录数据列级的操作权限
  5. host权限表:配合db权限表对给定主机上数据库级操作权限作更细致的
    控制。这个权限表不受GRANT和REVOKE语句的影响

binlog redolog undolog都是什么,起什么作用?

  1. redo log 重做日志,用来保证事务的持久性,基本是按顺序写的。在事务
    开始时就会产生redo log,逐步写入日志文件,归属于存储引擎
  2. undo log 回滚日志,用来帮助事务回滚及MVCC功能,需要进行随机读写
    ,保存了事务发生之前的一个版本,在事务提交之后 undo log 并不会马上
    删除,而是放入待清理的链表,purge线程判断是否由其他事务在使用undo
    段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志
    空间,归属于存储引擎
  3. binlog 二进制日志 归属于Server层,error log 和realy log 也是
    在Server层。记录所有与MySQL相关的日志记录,包括所有的存储引擎。用于
    PIT POINT-IN-TIME的恢复以及主从复制环境的建立

MySQL的binlog有有几种录入格式?分别有什么区别?

  1. statement模式下,每一条会修改数据的sql都会记录在binlog 中。不需
    要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。由于sql
    的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一
    些使用了函数之类的语句无法被记录复制
  2. row级别下,不记录sql语句上下文相关信息,仅保存哪条记录被修改。记
    录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致
    大量行的改动(比如alter table),因此这种模式的文件保存的信息太多
    ,日志量太大
  3. mixed,一种折中的方案,普通操作使用statement记录,当无法使用
    statement的时候使用row

MySQL 如何优化?

  1. 开启查询缓存,优化查询 可以查看缓存信息
  2. explain你的select查询,这可以帮你分析你的查询语句或是表结构的
    性能瓶颈。EXPLAIN的查询结果还会告诉你你的索引主键被如何利用的,你
    的数据表是如何被搜索和排序的
  3. 当只要一行数据时使用limit 1,MySQL数据库引擎会在找到一条数据
    后停止搜索,而不是继续往后查少下一条符合记录的数据
  4. 为搜索字段建索引
  5. 使用 ENUM 而不是 VARCHAR,有一个字段的情况
  6. 预编译 是一种运行在后台的SQL语句集合,可以检查一些你绑定好的变
    量,这样可以保护你的程序不会受到“SQL注入式”攻击
  7. 垂直分表

explain的作用?

Explain 用来分析 SELECT 查询语句,开发人员可以通过分析 Explain
结果来优化查询语句,并输出 SELECT 执行的详细信息,在 SELECT 语
句前加上 Explain 就可以了。能够获取的信息如下

  1. select_type 查询的类型,有简单查询、联合查询、子查询等
  2. key 此次查询中确切使用到的索引
  3. rows 扫描的行数
  4. id是用来顺序标识整个查询中SELELCT 语句的,在嵌套查询中id越大
    的语句越先执行。该值可能为NULL,如果这一行用来说明的是其他行的联
    合结果

MySQL 的explain关键字的select_type?

select的子句类型

  1. SIMPLE 简单select类型,不使用union和子查询的
  2. PRIMARY 查询中包任何复杂的子部分的最外层查询
  3. UNION union子句中的第二个或者往后的select

MySQL 的explain关键字的type?

表示mysql在表中找到所需行的方式,优化查询的关键字段

  1. system 表只有一行数据,const的特例
  2. const 表示该表只有一行匹配的数据,比如主键和唯一键的查询方式,
    速度仅次于system
  3. eq_ref 多只返回一条符合条件的记录。使用唯一性索引或主键查找时会
    发生
  4. ref 表示所有行都匹配索引值,表中有多行记录匹配,此类索引访问只有
    当使用非唯一性索引或唯一性索引非唯一性前缀时才会发生
  5. ALL 最坏的情况,全表扫描
  6. NULL 意味说mysql能在优化阶段分解查询语句,在执行阶段甚至用不到
    访问表或索引
  7. 范围扫描,一个有限制的索引扫描。key 列显示使用了哪个索引。当使用
    =、 <>、>、>=、<、<=、IS NULL、<=>、BETWEEN 或者 IN 操作符,用常量比
    较关键字列时,可以使用 range
  8. index 和全表扫描一样。只是扫描表的时候按照索引次序进行而不是行。
    如在Extra列看到Using index,说明正在使用覆盖索引,只扫描索引的数
    据,它比按索引次序全表扫描的开销要小很多

慢查询日志的作用?

某些sql语句执行完毕所花费的时间特别长,我们将这种响应比较慢的语句
记录在慢查询日志中,通过慢查询日志,可以查找出哪些查询语句的执行
效率低,以便进行优化。通过 slow_query_log[={0|1}]选项来启用慢
查询日志。所有执行时间超过long_query_time秒的SQL语句都会被记
录到慢查询日志

MySQL查询慢如何定位?

  1. show variables like ‘slow_query%’; 首先查看两个参数
  2. how variables like ‘long_query_time’; 查询慢查询时间
  3. show status like ‘slow_queries’; 显示慢查询次数
  4. set long_query_time = 1;
  5. set global slow_query_log=’ON’;
  6. show status like ‘slow_queries’; 查看慢查询的数量是否增加
  7. select sleep(2); 执行一条慢查询 SQL 语句

如何优化数据访问?

  1. 减少请求的数据量
  • 只返回必要的列:最好不要使用 SELECT * 语句。
  • 只返回必要的行:使用 LIMIT 语句来限制返回的数据。
  • 缓存重复查询的数据:使用缓存可以避免在数据库中进行查询,特别在要
    查询的数据经常被重复查询时,缓存带来的查询性能提升将会是非常明显的
  1. 减少服务器端扫描的行数
    最有效的方式是使用索引来覆盖查询

水平切分和垂直切分的区别?

  1. 水平切分 水平切分又称为 Sharding,它是将同一个表中的记录拆分到
    多个结构相同的表中。当一个表的数据不断增多时,Sharding 是必然的选
    择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力
  2. 垂直切分 垂直切分是将一张表按列切分成多个表,通常是按照列的关系
    密集程度进行切分,也可以利用垂直切分将经常被使用的列和不经常被使用
    的列切分到不同的表中。在数据库的层面使用垂直切分将按数据库中表的密
    集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据
    库、用户数据库等

索引设计的原则是什么?

  1. 适合索引的列是出现在where子句中的列,或者连接子句中指定的列
  2. 基数较小的类,索引效果较差,没有必要在此列建立索引
  3. 使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,这样
    能够节省大量索引空间
  4. 不要过度索引。索引需要额外的磁盘空间,并降低写操作的性能。在修改
    表内容的时候,索引会进行更新甚至重构,索引列越多,这个时间就会越长
    。所以只保持需要的索引有利于查询即可

创建索引的原则有哪些?

  1. 最左前缀匹配原则,组合索引非常重要的原则,mysql会一直向右匹配直到
    遇到范围查询(>、<、between、like)就停止匹配,比如a = 1 and b = 2and
    c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果
    建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整
  2. 较频繁作为查询条件的字段才去创建索引
  3. 更新频繁字段不适合创建索引
  4. 若是不能有效区分数据的列不适合做索引列。索引的选择性是指,不重复的
    索引值和数据表的记录总数的比值。索引的选择性越高则查询效率越高,因为
    选择性高的索引可以让MySQL在查找时过滤掉更多的行
  5. 尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)
    的索引,那么只需要修改原来的索引即可
  6. 定义有外键的数据列一定要建立索引
  7. 对于那些查询中很少涉及的列,重复值比较多的列不要建立索引

创建索引时需要注意什么?

  1. 非空字段:应该指定列为NOT NULL,除非你想存储NULL。在mysql中,
    含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以
    及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值
  2. 取值离散大的字段:(变量各个取值之间的差异程度)的列放到联合索引的
    前面,可以通过count()函数查看字段的差异值,返回值越大说明字段的唯一
    值越多字段的离散程度高
  3. 索引字段越小越好:数据库的数据存储以页为单位一页存储的数据越多一次
    IO操作获取的数据越大效率越高

表分区与分表的区别?

  1. 表分区 是指根据一定规则,将数据库中的一张表分解成多个更小的,容易
    管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成
  2. 分表 指的是通过一定规则,将一张表分解成多张不同的表,分区从逻辑上
    来讲只有一张表,而分表则是将一张表分解成多张表

表分区有什么好处?

  1. 分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备
    ,和单个磁盘或者文件系统相比,可以存储更多数据
  2. 优化查询 在where语句中包含分区条件时,可以只扫描一个或多个分区表
    来提高查询效率,涉及sum和count语句时,也可以在多个分区上并行处理,
    最后汇总结果
  3. 分区表更容易维护。例如:想批量删除大量数据可以清除整个分区
  4. 可以使用分区表来避免某些特殊的瓶颈,例如InnoDB的单个索引的互斥访问

分区表的限制因素?

  1. 一个表最多只能有1024个分区
  2. 如果分区字段中有主键或者唯一索引的列,那么多有主键列和唯一索引列
    都必须包含进来。即分区字段要么不包含主键或者索引列,要么包含全部主
    键和索引列
  3. 分区表中无法使用外键约束
  4. MySQL的分区适用于一个表的所有数据和索引,不能只对表数据分区而不对
    索引分区,也不能只对索引分区而不对表分区,也不能只对表一部分数据分区

MySQL支持的分区类型有哪些?

  1. RANGE分区:这种模式允许将数据划分不同范围。例如可以将一个表通过年
    份划分成若干个分区
  2. LIST分区:这种模式允许系统通过预定义的列表的值来对数据进行分割。
    按照List中的值分区,与RANGE的区别是,range分区的区间范围值是连续的
  3. HASH分区 :这中模式允许通过对表的一个或多个列的Hash Key进行计算
    ,最后通过这个Hash码不同数值对应的数据区域进行分区。例如可以建立一
    个对表主键进行分区的表
  4. KEY分区 :上面Hash模式的一种延伸,这里的Hash Key是MySQL系统产生的

drop、truncate和delete的区别?

  1. delete DELETE语句执行删除的过程是每次从表中删除一行,并且同时将
    该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作,会保留
    标识计数值
  2. truncate TRUNCATE TABLE 则一次性地从表中删除所有的数据并不把
    单独的删除操作记录记入日志保存,删除行是不能恢复的。并且在删除的过
    程中不会激活与表有关的删除触发器。执行速度快,会恢复到默认标识计
    数值
  3. drop drop语句删除表结构及所有数据,并将表所占用的空间全部释放

int(20)中20的含义?

int(20)的作用与int 的范围明显是无关的,int(20)只是用来显示数据的
宽度是20,当你输入的数据不足20位时,会自动帮你补全位数,范围固定
是4个字节

字段为什么要求定义为not null?

影响优化器对索引的选择,索引效率会下降很多,因为NULL是一种比较特殊
的数据类型。数据库在处理的时候,需要进行特殊的处理。就会增加数据库
处理记录的复杂性。当表中有比较多的空字段时,在同等条件下,数据库
处理的性能会降低许多

join的原理及应用?

  1. left join,保留左表所有数据,左边没有数据设置为 null
  2. right join,保留右表所有数据,游标没有数据设置为 null
  3. inner join,取左右表数据的交集

Oracle 和 MySQL 都使用了嵌套循环(Nested-Loop Join)的实现方式。
使用 Nested-Loop Join 算法,需要区分驱动表和被驱动表,先访问驱动表
,筛选出结果集,然后将这个结果集作为循环的基础,访问被驱动表过滤出需
要的数据

  1. SNLJ 简单嵌套循环,这里会扫描 A 表,将记录一行一行地取出来进行匹
    配。其实就是用A 的结果集做为外循环,读取每一行都会触发一个内循环(扫
    描B 表)。对B 表的数据进行比较,加入结果集
  2. INLJ 索引嵌套循环 整个算法过程和 SNL 一致,最大的区别在于,用来
    进行join 的字段已经在被驱动表中建立了索引。A 的行数为N,所以内循环
    个数没变也是N,因为还是要对 N 行 A 数据进行比较。但是内循环次数被
    优化了,之前的 SNLJ 算法,因为没有索引,每个内循环要扫码一次B表。
    有了索引后,不需要再全表扫描 B 表,而是进行 B 表的索引查询

建表时用了哪些索引?

  1. 聚集索引
  2. 非聚集索引
  3. 惟一索引
  4. 复合索引

当数据量很大时,如何优化?

  1. 创建索引
  2. 缓存的配置 由server端来维护的。它会随着你查询与修改等相应不同操
    作进行不断更新
  3. 分库分表
  4. 子查询优化
  5. 加速磁盘io,使用高速固态硬盘作数据库的交换临时文件存储

分布式事务?

  1. 不同的是单机事务只是在单机上执行,而分布式事务则是在多台机器上执行
    ,对于分布式数据库系统,事务的一系列操作序列会被拆分为子操作序列,然
    后在多台机器上执行
  2. 分布式事务同样具有ACID四个特性,但是因为分布式数据库的分布特性,使
    其又有一些不同,也叫全局事务,被拆分为在各个机器上执行的子操作序列,
    称为子事务
  3. 必须保证组成该全局事务的所有子事务要么全部提交,要么全部回滚,不允
    许出现有些场地上的子事务提交,而有些场地上的子事务回滚。分布式事务除了
    要保证各个子事务的ACID特性外,还需要对这些子事务进行协调,决定各个子
    事务的提交与回滚,以保证全局事务的ACID特性。另外,在分布式事务中,还
    涉及大量的网络通信,需要考虑到网络的影响

分布式事务的提交协议?

  1. 全局事务的正确执行依赖各个子事务的正确执行。只有当各个局部操作都
    正确执行后,全局事务才可以提交,当发生异常要回滚全局事务时,所有局
    部操作也应回滚
  2. 用两阶段提交协议,简称2PC协议,通过引入协调者来协调参与者的行为
    ,并最终决定这些参与者是否要真正执行事务
  3. 协调者:协调各个子事务的执行,负责决定所有子事务的提交或回滚
  4. 参与者:负责各个子事务的提交与回滚,并向协调者提出子事务的提交或
    回滚意向
  5. 协调者和每个参与者均拥有一个本地日志文件,用来记录各自的执行过程

两阶段提交协议的基本思想?

两阶段提交协议是为了实现分布式事务提交而采用的协议。其基本思想是把全
局事务的提交分为如下两个阶段

  1. 决定阶段 由协调者向各个参与者发出“预提交”(Prepare)命令,然后等
    待应答,若所有的参与者返回“准备提交”(Ready)应答,则该事务满足提交
    条件。如果至少有一个子事务返回“准备废弃”(Abort)应答,则该事务不能
    提交
  2. 执行阶段 在事务具备提交条件的情况下,协调者向各个参与者发出“提交”
    (Commit)命令,各个参与者执行提交;否则,协调者向各个参与者发出“废
    弃”(Abort)命令,各个参与者执行回滚,放弃对数据库的修改

分布式事务的缺点?

  1. 同步阻塞 所有事务参与者在等待其它参与者响应的时候都处于同步阻塞等
    待状态,无法进行其它操作
  2. 单点问题 在提交阶段发生故障,所有参与者会一直同步阻塞等待,无法完
    成其它操作
  3. 数据不一致 在提交阶段,如果协调者只发送了部分 Commit消息,此时网
    络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分
    参与者提交了事务,使得系统数据不一致
  4. 太过保守 任意一个节点失败就会导致整个事务失败,没有完善的容错机制

分布式了解吗?

分布式就是将一个系统的各个组件(MySQL、PHP、Apache …)分布在网络上的各
台主机, 并且各组件之间仅通过消息传递来通信并协调工作

分布式系统?

  1. 单块系统 将所有的代码都放在一个工程里,可能用maven等构件工具拆分
    一下代码工程模块,不同的模块可以放在不同的工程代码中
  2. 分布式系统 是一个硬件或软件组件分布在不同的网络计算机上,彼此之间
    仅仅通过消息传递进行通信和协调的系统

分布式和集群的区别?

  1. 分布式(distributed)是指在多台不同的服务器中部署不同的服务模块,
    通过远程调用协同工作,对外提供服务
  2. 集群(cluster)是指在多台不同的服务器中部署相同应用或服务模块,
    构成一个集群,通过负载均衡设备对外提供服务

可串行化会导致死锁吗?

会,当多个事务同时持有和请求同一资源上的锁而产生循环依赖的时候就产生
了死锁

hash跟b+在什么场景用?

  1. 如果是等值查询,那么hash索引具有绝对优势
  2. 范围查询检索,就需要用到B+树
  3. 如果存储的数据重复度很低(也就是说基数很大),对该列数据以等值查
    询为主,没有范围查询、没有排序的时候,特别适合采用哈希索引

分布式有了解过是吧?知道分布式事务吗?CAP?讲一下

  1. 分区容错性、高可用性、数据一致性;
  2. 三者不能同时满足,一般的分布式系统都会优先满足高可用、放弃强一致性
    选择最终一致性
  3. 从单应用架构的事务说起,介绍分布式事务的出现意义,目前分布式事务常
    用的2PC、3PC都讲了一下

联合索引的后面的索引存放在哪?

联合索引的所有索引列都出现在索引数上,并依次比较三列的大小

MySQL怎么做数据容灾

双机热备的概念简单说一下,就是要保持两个数据库的状态自动同步。对任何一
个数据库的操作都自动应用到另外一个数据库,始终保持两个数据库数据一致

  1. 可以做灾备,其中一个坏了可以切换到另一个
  2. 可以做负载均衡,可以将请求分摊到其中任何一台上,提高网站吞吐量

myisam为什么适合读多写少的情况,举个具体例子?

  1. 数据块,INNODB要缓存,MYISAM只缓存索引块,这中间还有换进换出的减少
  2. innodb寻址要映射到块,再到行,MYISAM记录的直接是文件的OFFSET,定
    位比INNODB要快
  3. INNODB还需要维护MVCC一致

MySQL 主从同步机制,如果同步失败会怎么样?

  1. 在主库那边(master)清除日志
  2. 重新执行

mysql主从复制原理?

  1. 主从复制,是用来建立一个和主数据库完全一样的数据库环境,称为从数
    据库,主数据库一般是准实时的业务数据库
  2. 作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避
    免数据丢失

主从复制的方式有5种

  1. 一主一从,基础的主从结构
  2. 主主复制(两个主机在同一等级上,没有主从之分)
  3. 一主多从,适用于增删改少,查询多的业务
  4. 多主一从适用于增删改较多,查询少的业务
  5. 联级复制

实现原理

  1. 数据库有个bin-log二进制文件,记录了所有sql语句
  2. 我们的目标就是把主数据库的bin-log文件的sql语句复制到从数据库
  3. 让其转为从数据库的relay-log中继日志,通过中继日志将主数据库中的
    SQL语句同步到从数据库,保证主从数据库一致
  4. 主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程
  • binlog输出线程:每当有从库连接到主库发送请求时,主库都会创建一个线
    程然后发送binlog内容到从库
    在从库里,当复制开始的时候,从库就会创建两个线程进行处理:
  • 从库I/O 线程:当START SLAVE 语句在从库开始执行之后,从库创建一个
    I/O线程,该线程连接到主库并请求主库发送binlog里面的更新记录到从库
    上。从库I/O线程读取主库的binlog输出线程发送的更新并拷贝这些更新到
    本地文件,其中包括relay log文件
  • 从库的SQL 线程:从库创建一个SQL 线程,这个线程读取从库I/O 线程写到
    relay log 的更新事件并执行

主从复制的优点?

  1. 实现服务器负载均衡 主服务器处理写操作以及实时性要求比较高的读操
    作,而从服务器处理读操作
  2. 确保数据安全 在从主服务器进行备份,避免备份期间影响主服务器服务
Author: 高明
Link: https://skysea-gaoming.github.io/2021/01/04/MySQL%E9%9D%A2%E8%AF%95%E9%A2%98/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.