【MySQL】必备终极技能篇(持续更新...)

文章目录

  • 1、事务
    • 1、1 基本概念
    • 1、2 人人都知道事务的四大特性:ACID
    • 1、3 但他们的实现原理是什么?
  • 2、日志
    • 2、1 重做日志(redo log)
    • 2、2回滚日志(undo log)
    • 2、3 二进制日志(binlog)
    • 2、4 错误日志(errorlog)
    • 2、5慢查询日志(slow query log)
    • 2、6一般查询日志(general log)
    • 2、7中继日志(relay log)
  • 3、锁
    • 3、1MySQL锁的基本介绍
    • 3、2 常见的3种锁
  • 4、mvcc
    • 4、1概念
    • 4、2基于锁的并发控制流程
    • 4、3接下来以innoDB为前提,举例说明mvcc
  • 5、存储引擎
    • 5、1概述
    • 5、2InnoDB存储引擎
    • 5、3MyISAM存储引擎
    • 5、4MEMORY存储引擎
    • 5、5MERGE存储引擎
  • 6、分库分表
    • 6、1分库分表出现的背景
    • 6、2垂直切分
    • 6、3水平切分(重点)
    • 6、4数据切分导致的一些问题
    • 6、5分库分表之后,数据源的管理是系统实现的关键。
  • 7、主从复制,读写分离
    • 7、1概述
    • 7、2主从复制的结果?
    • 7、3复制的几种方式(策略)?
    • 7、4主从复制的好处?
    • 7、5如何实现主从复制的?
  • 8、索引
    • 8、1 索引是什么?
    • 8、2 索引有哪几种类型?
    • 8、3 索引在哪里用?
    • 8、4 索引的数据结构的演变:
  • 9、MySQL性能优化
    • 9、1 SQL的性能优化之索引优化

1、事务

1、1 基本概念

  • 数据库事务是构成单一逻辑工作单元的操作集合

注意点:

  • 1 、数据库事务可以包含一个或多个数据库操作,但这些操作构成一个逻辑上的整体
  • 2、构成逻辑整体的这些数据库操作,要么全部执行成功,要么全部不执行
  • 3、构成事务的所有操作,要么全都对数据库产生影响,要么全都不产生影响,即不管事务是否执行成功,数据库总能保持一致性状态
  • 4、并发操作下,事务的控制尤为关键

1、2 人人都知道事务的四大特性:ACID

  • 原子性(Atomicity):事务中的所有操作作为一个整体像原子一样不可分割,要么全部成功,要么全部失败。
  • 一致性(Consistency):事务的执行结果必须使数据库从一个一致性状态到另一个一致性状态。一致性状态是指:
    • 1.系统的状态满足数据的完整性约束(主码,参照完整性,check约束等)
    • 2.系统的状态反应数据库本应描述的现实世界的真实状态,比如转账前后两个账户的金额总和应该保持不变。
  • 隔离性(Isolation):并发执行的事务不会相互影响,其对数据库的影响和它们串行执行时一样。比如多个用户同时往一个账户转账,最后账户的结果应该和他们按先后次序转账的结果一样。
  • 持久性(Durability):事务一旦提交,其对数据库的更新就是持久的。任何事务或系统故障都不会导致数据丢失。

1、3 但他们的实现原理是什么?

  • 事务的原子性是通过 undo log 来实现的

    • Undo Log是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用Undo Log来实现多版本并发控制(简称:MVCC)
    • 在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为Undo Log)。然后进行数据的修改。如果出现了错误或者用户执行了ROLLBACK语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态

      注意:undo log是逻辑日志,可以理解为:
    • 当delete一条记录时,undo log中会记录一条对应的insert记录
    • 当insert一条记录时,undo log中会记录一条对应的delete记录
    • 当update一条记录时,它记录一条对应相反的update记录
  • 事务的持久性是通过 redo log 来实现的

    和Undo Log相反,Redo Log记录的是新数据的备份。在事务提交前,只要将Redo Log持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,

    但是Redo Log已经持久化。系统可以根据Redo Log的内容,将所有数据恢复到最新的状态

    通过sql:SELECT @@innodb_flush_log_at_trx_commit可以查看当前表的undo log使用的哪一种
    【MySQL】必备终极技能篇(持续更新...)_第1张图片
    【MySQL】必备终极技能篇(持续更新...)_第2张图片
    当设置为0,该模式速度最快,但不太安全,mysqld进程的崩溃会导致上一秒钟所有事务数据的丢失。(原因是数据第一部存储在了日志内存中)

    当设置为1,该模式是最安全的,但也是最慢的一种方式。在mysqld 服务崩溃或者服务器主机crash的情况下,binary log 只有可能丢失最多一个语句或者一个事务(原因是数据直接存入了磁盘进行了持久化)

    当设置为2,该模式速度较快,也比0安全,只有在操作系统崩溃或者系统断电的情况下(原因是数据第一部存储在了系统内存中),上一秒钟所有事务数据才可能丢失。

  • 事务的隔离性是通过 (读写锁+MVCC)来实现的

    • 后面的模块进行介绍
  • 事务的一致性是通过原子性,持久性,隔离性来实现的!

Mysql事务的隔离级别:(隔离级别从上到下,由低到高)
【MySQL】必备终极技能篇(持续更新...)_第3张图片

2、日志

MySQL中有七种日志文件,分别是:

2、1 重做日志(redo log)

  • 1、作用

    • 确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。
  • 2、内容

    • 物理格式的日志,记录的是物理数据页面的修改的信息,其redo log是顺序写入redo log file的物理文件中去的。
  • 3、什么时候产生
    事务开始之后就产生redo log,redo log的落盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo log文件中。

  • 4、什么时候释放

    • 当对应事务的脏页写入到磁盘之后,redo log的使命也就完成了,重做日志占用的空间就可以重用(被覆盖)。
  • 5、对应的物理文件

    • 默认情况下,对应的物理文件位于数据库的data目录下的ib_logfile1&ib_logfile2

      innodb_log_group_home_dir 指定日志文件组所在的路径,默认./ ,表示在数据库的数据目录下。innodb_log_files_in_group 指定重做日志文件组中文件的数量,默认2

      关于文件的大小和数量,由一下两个参数配置

      innodb_log_file_size 重做日志文件的大小。

      innodb_mirrored_log_groups 指定了日志镜像文件组的数量,默认1

  • 6、其他

    • 很重要一点,redo log是什么时候写盘的?前面说了是在事物开始之后逐步写盘的。

      之所以说重做日志是在事务开始之后逐步写入重做日志文件,而不一定是事务提交才写入重做日志缓存,

      原因就是,重做日志有一个缓存区Innodb_log_buffer,Innodb_log_buffer的默认大小为8M(这里设置的16M),Innodb存储引擎先将重做日志写入innodb_log_buffer中。

2、2回滚日志(undo log)

  • 1、作用

    • 保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读
  • 2、内容

    • 逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的。
  • 3、什么时候产生

    • 事务开始之前,将当前是的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性
  • 4、什么时候释放

    • 当事务提交之后,undo log并不能立马被删除,

      而是放入待清理的链表,由purge线程判断是否由其他事务在使 用undo段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志空间。

  • 5、对应的物理文件

    • MySQL5.6之前,undo表空间位于共享表空间的回滚段中,共享表空间的默认的名称是ibdata,位于数据文件目录中。

      MySQL5.6之后,undo表空间可以配置成独立的文件,但是提前需要在配置文件中配置,完成数据库初始化后生效且不可改变undo log文件的个数

      如果初始化数据库之前没有进行相关配置,那么就无法配置成独立的表空间了。

      关于MySQL5.7之后的独立undo 表空间配置参数如下:

      innodb_undo_directory = /data/undospace/ –undo独立表空间的存放目录

      innodb_undo_logs = 128 –回滚段为128KB

      innodb_undo_tablespaces = 4 –指定有4个undo log文件

      如果undo使用的共享表空间,这个共享表空间中又不仅仅是存储了undo的信息,共享表空间的默认为与MySQL的数据目录下面,其属性由参数innodb_data_file_path配置。

  • 6、其他

    • undo是在事务开始之前保存的被修改数据的一个版本,产生undo日志的时候,同样会伴随类似于保护事务持久化机制的redolog的产生。

      默认情况下undo文件是保持在共享表空间的,也即ibdatafile文件中,当数据库中发生一些大的事务性操作的时候,要生成大量的undo信息,全部保存在共享表空间中的。

      因此共享表空间可能会变的很大,默认情况下,也就是undo 日志使用共享表空间的时候,被“撑大”的共享表空间是不会也不能自动收缩的。

      因此,mysql5.7之后的“独立undo 表空间”的配置就显得很有必要了。

2、3 二进制日志(binlog)

  • 1、作用

    • 用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步;

    用于数据库的基于时间点的还原;

  • 2、内容

    • 逻辑格式的日志,可以简单认为就是执行过的事务中的sql语句。

      但又不完全是sql语句这么简单,而是包括了执行的sql语句(增删改)反向的信息,

      也就意味着delete对应着delete本身和其反向的insert;update对应着update执行前后的版本的信息;insert对应着delete和insert本身的信息。

      在使用mysqlbinlog解析binlog之后一些都会真相大白。

      因此可以基于binlog做到类似于oracle的闪回功能,其实都是依赖于binlog中的日志记录。

  • 3、什么时候产生

    • 事务提交的时候,一次性将事务中的sql语句(一个事物可能对应多个sql语句)按照一定的格式记录到binlog中。

      这里与redo log很明显的差异就是redo log并不一定是在事务提交的时候刷新到磁盘,redo log是在事务开始之后就开始逐步写入磁盘。

      因此对于事务的提交,即便是较大的事务,提交(commit)都是很快的,但是在开启了bin_log的情况下,对于较大事务的提交,可能会变得比较慢一些。

      这是因为binlog是在事务提交的时候一次性写入的造成的,这些可以通过测试验证。

  • 4、什么时候释放

    • binlog的默认是保持时间由参数expire_logs_days配置,也就是说对于非活动的日志文件,在生成时间超过expire_logs_days配置的天数之后,会被自动删除。
  • 5、对应的物理文件

    • 配置文件的路径为log_bin_basename,binlog日志文件按照指定大小,当日志文件达到指定的最大的大小之后,进行滚动更新,生成新的日志文件。

      对于每个binlog日志文件,通过一个统一的index文件来组织。

  • 6、其他

    • 二进制日志的作用之一是还原数据库的,这与redo log很类似,很多人混淆过,但是两者有本质的不同:

      • 作用不同:redo log是保证事务的持久性的,是事务层面的,binlog作为还原的功能,是数据库层面的(当然也可以精确到事务层面的),虽然都有还原的意思,但是其保护数据的层次是不一样的。

      • 内容不同:redo log是物理日志,是数据页面的修改之后的物理记录,binlog是逻辑日志,可以简单认为记录的就是sql语句

      • 另外,两者日志产生的时间,可以释放的时间,在可释放的情况下清理机制,都是完全不同的。

      • 恢复数据时候的效率,基于物理日志的redo log恢复数据的效率要高于语句逻辑日志的binlog

      • 关于事务提交时,redo log和binlog的写入顺序,为了保证主从复制时候的主从一致(当然也包括使用binlog进行基于时间点还原的情况),是要严格一致的,

      • MySQL通过两阶段提交过程来完成事务的一致性的,也即redo log和binlog的一致性的,理论上是先写redo log,再写binlog,两个日志都提交成功(刷入磁盘),事务才算真正的完成。

2、4 错误日志(errorlog)

  • 在mysql数据库中,错误日志功能是默认开启的。并且,错误日志无法被禁止。默认情况下,错误日志存储在mysql数据库的数据文件中。错误日志文件通常的名称为hostname.err。其中,hostname表示服务器主机名。

    错误日志信息可以自己进行配置的,错误日志所记录的信息是可以通过log-error和log-warnings来定义的,其中log-err是定义是否启用错误日志的功能和错误日志的存储位置,log-warnings是定义是否将警告信息也定义至错误日志中。默认情况下错误日志大概记录以下几个方面的信息:服务器启动和关闭过程中的信息(未必是错误信息,如mysql如何启动InnoDB的表空间文件的、如何初始化自己的存储引擎的等等)、服务器运行过程中的错误信息、事件调度器运行一个事件时产生的信息、在从服务器上启动服务器进程时产生的信息。

2、5慢查询日志(slow query log)

  • 慢查询日志是用来记录执行时间超过指定时间的查询语句。通过慢查询日志,可以查找出哪些查询语句的执行效率很低,以便进行优化。一般建议开启,它对服务器性能的影响微乎其微,但是可以记录mysql服务器上执行了很长时间的查询语句。可以帮助我们定位性能问题的。

  • 查看慢查询日志的定义:

    mysql> SHOW GLOBAL VARIABLES LIKE ‘%log%’;
    | slow_query_log | OFF #定义慢查询日志的
    | slow_query_log_file |/mydata/data/stu18-slow.log #输出方式为file(文件)时定义慢查询日志的位置

2、6一般查询日志(general log)

  • 默认情况下查询日志是关闭的。由于查询日志会记录用户的所有操作,其中还包含增删查改等信息,在并发操作大的环境下会产生大量的信息从而导致不必要的磁盘IO,会影响mysql的性能的。如若不是为了调试数据库的目的建议不要开启查询日志。

2、7中继日志(relay log)

  • relay log是复制过程中产生的日志,很多方面都跟bin log差不多,区别是: relay log是从库服务器I/O线程将主库服务器的二进制日志读取过来记录到从库服务器本地文件,然后从库的SQL线程会读取relay-log日志的内容并应用到从库服务器上。

3、锁

3、1MySQL锁的基本介绍

锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的 计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一 个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度来说,锁对数据库而言显得尤其重要,也更加复杂。

相对其他数据库而言,MySQL的锁机制比较简单,其最 显著的特点是不同的存储引擎支持不同的锁机制。比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

3、2 常见的3种锁

  • 行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁。行级锁能大大减少数据库操作的冲突。其加锁粒度最小,但加锁的开销也最大。行级锁分为共享锁 和 排他锁。

    特点:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

  • 表级锁 表级锁是MySQL中锁定粒度最大的一种锁,表示对当前操作的整张表加锁,它实现简单,资源消耗较少,被大部分MySQL引擎支持。最常使用的MYISAM与INNODB都支持表级锁定。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁)。

    特点:开销小,加锁快;不会出现死锁;锁定粒度大,发出锁冲突的概率最高,并发度最低。

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

    特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般

从上述特点可见,很难笼统地说哪种锁更好,只能就具体应用的特点来说哪种锁更合适!仅从锁的角度 来说:表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用;而行级锁则更适合于有大量按索引条件并发更新少量不同数据,同时又有 并发查询的应用,如一些在线事务处理(OLTP)系统。

4、mvcc

4、1概念

英文全称为Multi-Version Concurrency Control,中文: 多版本并发控制,通过使用mvcc算法自动提供并发控制。mvcc可以维持一个数据的多个版本使读写操作没有冲突

本质来看其实mvcc是一种乐观锁的实现!

前面也说过,事务的隔离性(事务的隔离性:并发事务之间互不影响),是由锁+mvcc的方式实现的

4、2基于锁的并发控制流程

  • 事务根据自己对数据项进行的操作类型申请相应的锁(申请共享锁,申请排他锁)
  • 申请锁的请求被发送给锁管理器。锁管理器根据当前数据项是否已经有锁以及申请的和持有的锁是否冲突决定是否为该请求授予锁。
  • 若锁被授予,则申请锁的事务可以继续执行;若被拒绝,则申请锁的事务将进行等待,直到锁被其他事务释放。

mvcc说起来也是分存储引擎的,因为锁是分存储引擎的

InnoDB:通过为每一行记录添加两个额外的隐藏的值来实现mvcc,这两个值一个记录这行 数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。但是InnoDB并不存储这些事件发生时的实际时间,相反它只存储这些事件发生时的系统版 本号。这是一个随着事务的创建而不断增长的数字。每个事务在事务开始时会记录它自己的系统版本号。每个查询必须去检查每行数据的版本号与事务的版本号是否相同。

4、3接下来以innoDB为前提,举例说明mvcc

1、版本链

我们先来理解一下版本链(链的概念就是地址)的概念。在InnoDB引擎表中,它的聚簇索引记录中有两个必要的隐藏列:

  • trx_id
    这个id用来存储的每次对某条聚簇索引记录进行修改的时候的事务id。

  • roll_pointer
    每次对哪条聚簇索引记录有修改的时候,都会把老版本写入undo日志中。这个roll_pointer就是存了一个指针,它指向这条聚簇索引记录的上一个版本的位置,通过它来获得上一个版本的记录信息。(注意插入操作的undo日志没有这个属性,因为它没有老版本)

先插入一列:执行insert ,假设这个表只有两个字段

id name trx_id roll_pointer
1 sjt 10 新纪录没有老版本

现在执行update,将sjt改为sjt1

id name trx_id roll_pointer
1 sjt1 20 上一个版本的地址(即下面这条记录的地址)
1 sjt 10 新纪录没有老版本

此时在undo日志中就存在版本链

2、ReadView
ReadView中主要就是有个列表来存储我们系统中当前活跃着的读写事务,也就是开始了还未提交的事务。通过这个列表来判断记录的某个版本是否对当前事务可见。

比如,当前活跃的事务的事务id(TRX_ID )为[50,70](注意这里的意义是集合,不是范围

当你访问事务id不在这个集合内的时候,是可以访问的(比如,40,60等等),因为事务都已经提交,当你访问的事务id在这个集合内的时候([50,70]),你不能访问,因为事务还没提交。(这个列表就是ReadView)

但需要注意,readView在不同的隔离级别也是不同的:
已提交读和可重复读的区别就在于它们生成ReadView的策略不同。

比如,在已提交读隔离级别下:

在次update,但事务id为30的这次事务没有提交,所以此时的ReadView中只有[30]

id name trx_id roll_pointer
1 sjt2 30 上一个版本的地址(即下面这条记录的地址)
1 sjt1 20 上一个版本的地址(即下面这条记录的地址)
1 sjt 10 新纪录没有老版本

这时,另外一个事务B来访问id为1的这条记录,它找到了事务id为30的这条记录,但是,事务id为30的事务在ReadView中,所以不能访问,事务B他没拿到最新的记录,所以,就会通过roll_pointer存储的地址,找到trx_id为20的记录,此时检查是否在ReadView中,不在,所以拿到了这条记录

这时我们把事务id为30的事务,提交,在此update一次(这次事务id为40,也没提交)

id name trx_id roll_pointer
1 sjt3 40 上一个版本的地址(即下面这条记录的地址)
1 sjt2 30 上一个版本的地址(即下面这条记录的地址)
1 sjt1 20 上一个版本的地址(即下面这条记录的地址)
1 sjt 10 新纪录没有老版本

这个时候关键的地方来了

如果你是已提交读隔离级别,这时候你会重新一个有ReadView,那你的活动事务列表中的值就变了,变成了[40]。

按照上的说法,你去版本链通过trx_id对比查找到合适的结果就是sjt2。

如果你是可重复读隔离级别,这时候你的ReadView还是第一次select时候生成的ReadView,也就是列表的值还是[30]。所以访问的结果是sjt1。所以第二次访问结果和第一次一样,所以叫可重复读!

也就是说已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的时候生成一个ReadView,之后的读都复用之前的ReadView。

5、存储引擎

5、1概述

数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎,还可以 获得特定的功能。现在许多不同的数据库管理系统都支持多种不同的数据引擎。数据库的核心就是存储引擎,MySQL默认的存储引擎是InoDB

我们常见(常用)的其实就前两种,需要注意的是:存储引擎是表级别的,也就是说不同的表可以有不同的存储引擎

5、2InnoDB存储引擎

InnoDB是事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键,InnoDB是默认的MySQL引擎。

InnoDB主要特点:

  • 1、InnoDB给MySQL提供了具有提交、回滚和崩溃恢复能力的事物安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在SELECT语句中提供一个类似Oracle的非锁定读。这些功能增加了多用户部署和性能。在SQL查询中,可以自由地将InnoDB类型的表和其他MySQL的表类型混合起来,甚至在同一个查询中也可以混合

  • 2、InnoDB是为处理巨大数据量的最大性能设计。它的CPU效率可能是任何其他基于磁盘的关系型数据库引擎锁不能匹敌的

  • 3、InnoDB存储引擎完全与MySQL服务器整合,InnoDB存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。InnoDB将它的表和索引在一个逻辑表空间中,表空间可以包含数个文件(或原始磁盘文件)。这与MyISAM表不同,比如在MyISAM表中每个表被存放在分离的文件中。InnoDB表可以是任何尺寸,即使在文件尺寸被限制为2GB的操作系统上

  • 4、InnoDB支持外键完整性约束,存储表中的数据时,每张表的存储都按主键顺序存放,如果没有显示在表定义时指定主键,InnoDB会为每一行生成一个6字节的ROWID,并以此作为主键

  • 5、InnoDB被用在众多需要高性能的大型数据库站点上

InnoDB不创建目录,使用InnoDB时,MySQL将在MySQL数据目录下创建一个名为ibdata1的10MB大小的自动扩展数据文件,以及两个名为ib_logfile0和ib_logfile1的5MB大小的日志文件

使用innoDB的时候:会创建下面的两个文件
【MySQL】必备终极技能篇(持续更新...)_第4张图片frm文件存储表结构,ibd文件存储索引和数据(聚集索引)

5、3MyISAM存储引擎

MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事物。

MyISAM主要特性有:

  • 1、大文件(达到63位文件长度)在支持大文件的文件系统和操作系统上被支持

  • 2、当把删除和更新及插入操作混合使用的时候,动态尺寸的行产生更少碎片。这要通过合并相邻被删除的块,以及若下一个块被删除,就扩展到下一块自动完成

  • 3、每个MyISAM表最大索引数是64,这可以通过重新编译来改变。每个索引最大的列数是16

  • 4、最大的键长度是1000字节,这也可以通过编译来改变,对于键长度超过250字节的情况,一个超过1024字节的键将被用上

  • 5、BLOB和TEXT列可以被索引

  • 6、NULL被允许在索引的列中,这个值占每个键的0~1个字节

  • 7、所有数字键值以高字节优先被存储以允许一个更高的索引压

  • 8、每个MyISAM类型的表都有一个AUTO_INCREMENT的内部列,当INSERT和UPDATE操作的时候该列被更新,同时AUTO_INCREMENT列将被刷新。所以说,MyISAM类型表的AUTO_INCREMENT列更新比InnoDB类型的AUTO_INCREMENT更快

  • 9、可以把数据文件和索引文件放在不同目录

  • 10、每个字符列可以有不同的字符集

  • 11、有VARCHAR的表可以固定或动态记录长度

  • 12、VARCHAR和CHAR列可以多达64KB

使用MyISAM引擎创建数据库,将产生3个文件。文件的名字以表名字开始,扩展名之处文件类型:frm文件存储表定义、数据文件的扩展名为.MYD(MYData)、索引文件的扩展名时.MYI(MYIndex)
在这里插入图片描述

5、4MEMORY存储引擎

MEMORY存储引擎将表中的数据存储到内存中,未查询和引用其他表数据提供快速访问。
MEMORY主要特性有:

  • 1、MEMORY表的每个表可以有多达32个索引,每个索引16列,以及500字节的最大键长度

  • 2、MEMORY存储引擎执行HASH和BTREE缩影

  • 3、可以在一个MEMORY表中有非唯一键值

  • 4、MEMORY表使用一个固定的记录长度格式

  • 5、MEMORY不支持BLOB或TEXT列

  • 6、MEMORY支持AUTO_INCREMENT列和对可包含NULL值的列的索引

  • 7、MEMORY表在所由客户端之间共享(就像其他任何非TEMPORARY表)

  • 8、MEMORY表内存被存储在内存中,内存是MEMORY表和服务器在查询处理时的空闲中,创建的内部表共享

  • 9、当不再需要MEMORY表的内容时,要释放被MEMORY表使用的内存,应该执行DELETE FROM或TRUNCATE TABLE,或者删除整个表(使用DROP TABLE)

5、5MERGE存储引擎

Merge存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同,merge表本身并没有数据,对merge类型的表可以进行查询,更新,删除操作,这些操作实际上是对内部的MyISAM表进行的。
【MySQL】必备终极技能篇(持续更新...)_第5张图片

6、分库分表

6、1分库分表出现的背景

由于千万级别,甚至上亿的数据量导致单表单库操作压力过大,执行速度过慢…

简单来讲,分库分表只是一种优化策略,不是什么技术。

不论分库还是分表,我们的核心思想就是,数据切分

  • 数据切分(Sharding),简单的来说,就是通过某种特定的条件,将存放在同一个数据库中的数据拆分存放到多个数据库(主机)中,从而达到分散单台机器负载的情况,即分库分表。根据数据切分规则的不同,主要有两种模式,
    • 垂直切分(纵向切分),是对不同的表(或者Schema)进行切分,存储到不同的数据库(主机)之上。
    • 水平切分(横向切分),是对同一个表中的数据进行切分,存储到不同的数据库(主机)之上。规则是根据表中数据的逻辑关系,按照某种条件拆分。

接下来分别看这两种模式

6、2垂直切分

垂直切分,强调的是业务的拆分。一个数据库由多个表构成,每个表对应不同的业务,那么我们可以指按照业务的不同将表进行分类,并将其分布到不同的数据库上,这样就将数据分摊到了不同的库上面,做到专库专用。

举个例子,原数据库中有商品表、交易表、订单表,我们可以按照业务的不同进行垂直切分,把商品表、交易表、订单表分别拆分到商品库、交易库、订单库中去。

垂直拆分的优点:

  • 拆分规则明确,拆分后业务清晰;
  • 系统之间进行整合或扩展变的容易;
  • 数据维护变的容易;
  • 按照成本、应用的等级、应用的类型等将表放到不同的机器上,便于管理。

垂直拆分的缺点:

  • 部分业务表无法关联(Join),只能通过接口方式解决,提高了系统的复杂度;
  • 受每种业务的不同限制,存在单库性能瓶颈,不易进行数据扩展和提升性能;
  • 分布式事务处理复杂。

6、3水平切分(重点)

水平切分,强调的是技术层面的拆分。她是将其按照一定的逻辑规则将一个表中的数据分散到多个库中,在每个表中包含一部分数据,所有表加起来就是全量的数据。简单来说,我们可以将对数据的水平切分理解为按照数据行进行切分,就是将表中的某些行切分到一个数据库表中,而将其他行切分到其他数据库表中。

比如,原数据库有一张交易记录表,数据量非常大,其中表中有个地区字段,经过深入考证符合水平拆分的条件。我们就按照这个字段进行水平拆分,按不同的地区(北京、上海、江苏、浙江、广东等)拆分成10个库。

高峰时段同时有100万次请求,如果是单库,数据库就会承受100万次的请求压力,拆分成100个表分别放入10个库中,每个表进行1万次请求,则每个数据库会承受10万次的请求压力,这样压力就减少了很多,并且是成倍减少的。

水平拆分的优点:

  • 拆分规则抽象好,join 操作基本可以数据库做;
  • 不存在单库大数据,高并发的性能瓶颈;
  • 应用端改造较少;
  • 提高了系统的稳定性跟负载能力。

水平拆分的缺点:

  • 拆分规则不好抽象;
  • 分片事务一致性难以解决;
  • 数据多次扩展难度大;
  • 跨库 join 性能较差。

6、4数据切分导致的一些问题

上面我们也讲了两种数据切分方式的优点和缺点,但是他们有些共同的缺点,

  • 分布式事务的问题;

  • 跨节点 Join 的问题;跨节点合并排序分页的问题;

  • 多数据源管理问题。

  • 一般来说,业务上存在着复杂 join 的场景是很难切分的,往往业务独立的易于切分。如何切分,我们遵循如下原则,

  • 能不切分尽量不要切分;

  • 如果要切分一定要选择合适的切分规则,提前规划好;

  • 数据切分尽量通过数据冗余或表分组来降低跨库 Join 的可能;

  • 由于数据库中间件对数据 Join 实现的优劣难以把握,而且实现高性能难度极大,业务读取尽量少使用多表 Join。

6、5分库分表之后,数据源的管理是系统实现的关键。

系统应用层面
系统应用代码层面,目前主要有两种思路,

  • 客户端模式
    也就是在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个数据库,在模块内完成数据的整合。比如可以依赖spring注解实现。

    中间代理模式,统一管理所有的数据源,后端数据库集群对前端应用程序透明。

    考虑到系统的复杂性和扩展性,建议第二种中间代理模式。虽然短期内需要付出的成本可能会相对更大一些,但是对整个系统的扩展性来说,是非常实用的。

  • 中间件层面
    上面的系统层面,需要的代码实现比较复杂,中间件是在数据集群前面加一层代理,比如Cobar、Mycat等数据库中间件。实用数据库中间件,对代码层面的实现是很大的解放。

7、主从复制,读写分离

7、1概述

为什么需要主从复制,读写分离这种策略呢?

原因是:随着数据量的增长,到达瓶颈之后,数据操作效率会变得很低,甚至不可用,所以我们要将读/写分离开,以此来缓解单库的压力,虽然读写分离,但是主从库的数据得是同步的,否则读写分离,就没有了意义!
【MySQL】必备终极技能篇(持续更新...)_第6张图片
仔细观察上图可以发现,主从库用的日志是不同的,主库用的是专门用来保存修改数据库表的所有动作的日志,即bin log,从库用的是中继日志。

在主库的数据发生变化之后,底层的日志系统运作,(之前已经介绍过日志系统),来使主库的数据变化,同样的发生在从库里。

这样读写分离得以运行,从而达到我们减轻单库压力的目的。

7、2主从复制的结果?

复制的结果是集群(Cluster)中的所有数据库服务器得到的数据理论上都是一样的,都是同一份数据,只是有多个copy。MySQL默认内建的复制策略是异步的,基于不同的配置,Slave不一定要一直和Master保持连接不断的复制或等待复制,我们可以指定复制所有的数据库,一部分数据库,甚至是某个数据库的某部分的表。

7、3复制的几种方式(策略)?

  • 同步策略:Master要等待所有Slave应答之后才会提交(MySql对DB操作的提交通常是先对操作事件进行二进制日志文件写入然后再进行提交)。
  • 半同步策略:Master等待至少一个Slave应答就可以提交。(由google为MySQL引入的。)
  • 异步策略:Master不需要等待Slave应答就可以提交。(类似ajax请求,异步策略也是MySQL默认的复制策略)
  • 延迟策略:Slave要至少落后Master指定的时间。

7、4主从复制的好处?

  • 性能方面:MySQL复制是一种Scale-out方案,也即“水平扩展”,将原来的单点负载扩散到多台Slave机器中去,从而提高总体的服务性能。在这种方式下,所有的写操作,当然包括UPDATE操作,都要发生在Master服务器上。读操作发生在一台或者多台Slave机器上。这种模型可以在一定程度上提高总体的服务性能,Master服务器专注于写和更新操作,Slave服务器专注于读操作,我们同时可以通过增加Slave服务器的数量来提高读服务的性能。——实现“读”与“写”分离
  • 故障恢复:同时存在多台Slave提供读操作服务,如果有一台Slave挂掉之后我们还可以从其他Slave读取,如果配置了主从切换的话,当Master挂掉之后我们还可以选择一台Slave作为Master继续提供写服务,这大大增加了应用的可靠性。
  • 数据分析:实时数据可以存储在Master,而数据分析可以从Slave读取,这样不会影响Master的性能。

7、5如何实现主从复制的?

mysql主从复制需要三个线程,master(binlog dump thread)、slave(I/O thread 、SQL thread)。

  • master
    binlog dump线程:当主库中有数据更新时,那么主库就会根据按照设置的binlog格式,将此次更新的事件类型写入到主库的binlog文件中,此时主库会创建log dump线程通知slave有数据更新,当I/O线程请求日志内容时,会将此时的binlog名称和当前更新的位置同时传给slave的I/O线程。
    slave
  • I/O线程:该线程会连接到master,向log dump线程请求一份指定binlog文件位置的副本,并将请求回来的binlog存到本地的relay log中,relay log和binlog日志一样也是记录了数据更新的事件,它也是按照递增后缀名的方式,产生多个relay log( host_name-relay-bin.000001)文件,slave会使用一个index文件( host_name-relay-bin.index)来追踪当前正在使用的relay log文件。
  • SQL线程:该线程检测到relay log有更新后,会读取并在本地做redo操作,将发生在主库的事件在本地重新执行一遍,来保证主从数据同步。此外,如果一个relay log文件中的全部事件都执行完毕,那么SQL线程会自动将该relay log 文件删除掉。

8、索引

8、1 索引是什么?

索引说到底,它就是帮助MySQL高效获取数据的排好序的数据结构,就像是一本书的目录一般

8、2 索引有哪几种类型?

  • 主键索引: 数据列不允许重复,不允许为NULL,一个表只能有一个主键。

  • 唯一索引: 数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。

    可以通过 ALTER TABLE table_name ADD UNIQUE (column); 创建唯一索引

    可以通过 ALTER TABLE table_name ADD UNIQUE (column1,column2); 创建唯一组合索引

  • 普通索引: 基本的索引类型,没有唯一性的限制,允许为NULL值。

    可以通过ALTER TABLE table_name ADD INDEX index_name (column);创建普通索引

    可以通过ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);创建组合索引

  • 全文索引: 是目前搜索引擎使用的一种关键技术。

    可以通过ALTER TABLE table_name ADD FULLTEXT (column);创建全文索引

8、3 索引在哪里用?

说简单一点:where,order by,join这些关键字后面的字段,一般需要使用来进行SQL优化

8、4 索引的数据结构的演变:

  • 二叉树:这种数据结构,索引数据单边增长的时候,查找不方便
    【MySQL】必备终极技能篇(持续更新...)_第7张图片
    二叉树的深度会越来越深,查找的代价也会越来越大
  • 红黑树(自平衡二叉树):这种数据结构的缺点呢是:当索引数据量过大的时候,树的高度会过高
    【MySQL】必备终极技能篇(持续更新...)_第8张图片
  • Hash表:hash表做索引的时候,只需做一次哈希运算就能找到对应的那一行数据,但是,当时的搜索条件是范围查询(大于之类的)就不能用了。而我们实际的业务中很多也都是范围查询,等值查询很少。
  • B-Tree:一个节点存放很多个节点,(同样还是左边小,右边大)b树解决了二叉树和红黑树的弊端,但还是不能范围查找
    • b树的叶子节点具有相同的深度
    • b树的叶子节点指针为空
    • 节点中的数据索引从左到右递增排列
      【MySQL】必备终极技能篇(持续更新...)_第9张图片
  • B+树:mysql官方默认规定一行总共存储节点是16k,当然可以设置。假设如果是3层的B+树,存满可以存储2000W+行数据(正常字段存储)
    • 非叶子节点不存储数据,只存储索引, 这样就可以放更多的索引
    • 叶子节点不存储指针
    • 顺序访问指针,提高区间访问能力
      【MySQL】必备终极技能篇(持续更新...)_第10张图片
      b+树比b树的一个进步就是,将数据(data)全部存储在叶子节点,这样非叶子节点就可以存储更多的节点,这样就可以存储更多的data,至于范围查找,B+树的叶子节点之间是有双向指针的。
      图中的空白之处存的就是下一个节点的位置。

数据结构在线动态查看网站:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

9、MySQL性能优化

9、1 SQL的性能优化之索引优化

索引优化使用的是最左匹配原则

优化过程的调试,使用explain关键字即可

EXPLAIN关键字的使用:

  • EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
  • EXPLAIN不考虑各种Cache
  • EXPLAIN不能显示MySQL在执行查询时所作的优化工作
  • 部分统计信息是估算的,并非精确值
  • EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。

例如:
在这里插入图片描述
字段含义如下

  • id:选择标识符
  • select_type:表示查询的类型。
  • table:输出结果集的表
  • partitions:匹配的分区
  • type:表示表的连接类型
  • possible_keys:表示查询时,可能使用的索引
  • key:表示实际使用的索引
  • key_len:索引字段的长度
  • ref:列与索引的比较
  • rows:扫描出的行数(估算的行数)
  • filtered:按表条件过滤的行百分比
  • Extra:执行情况的描述和说明

下面的例子可以很好的理解最左匹配原则
【MySQL】必备终极技能篇(持续更新...)_第11张图片
注意:第四条虽然用到了索引,但只用到了name这个索引,这就是单表索引优化的原则只一:在联合索引中 范围以后的索引会导致索引失效

1、只要列中包含有NULL值都将不会被包含在索引中

2、复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的,所以我们在数据库设计时尽可能不要让字段的默认值为NULL。

MySQL整体的性能,初次之外,库,表,字段,字段大小,等等一切的细节,都是保证MySQL性能的重要组成。SQL优化,是后事

你可能感兴趣的:(数据库)