mysql 高级

MySQL高级

ACID

A:原子性,由 undo log 日志保证,它记录了需要回滚的日志信息,事务回滚时撤销已经执行成功的sql

C:一致性,由其它三大特征保证,程序代码要保证业务上的一致性

I:隔离性,由 MVCC 来保证

D:持久性,由内存 + redo log 来保证,mysql 修改数据,同时在内存和 redo log 记录这次操作,宕机的时候可以从 redo log 恢复

1
2
InnoDB redo log 写盘,InnoDB 事务进入 prepare 状态。
如果前面 prepare 成功,binlog 写盘,再继续将事务日志持久化到 binlog,如果持久化成功,那么 InnoDB 事务则进入 commit 状态(在 redo log 里面写一个 commit 记录)

redo log 的刷盘会在系统空闲时进行。

mysql 的结构介绍

  1. mysql 内核
  2. sql 优化工程师
  3. mysql 服务器的优化
  4. 各种参数常量设定
  5. 查询语句优化
  6. 主从复制
  7. 软硬件升级
  8. 容灾备份
  9. sql 编程

1、mysql 文件目录

路径 解释 备注
/var/lib/mysql/ mysql 数据库文件的存放路径 /var/lib/mysql/atguigu.cloud.pid
/usr/share/mysql 配置文件目录 mysql.server 命令及配置文件
/usr/bin 相关命令目录 mysqladmin mysqldump 等命令
/etc/init.d/mysql 启停相关脚本

2、修改配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
# windows 上为 my.ini 文件
vim /etc/my.cnf

# 设置字符编码
default-character-set=utf8

character_set_server=utf8
character_set_client=utf8
collation-server=utf8_general_ci

# 索引缓冲大小
sort_buffer_size =

3、日志文件

1
2
3
4
5
6
7
8
9
# 主从复制
log-bin=[path]
log-err=[path]

# 默认是关闭的,记录严重的警告和错误信息,每次启动和关闭的详细信息等
log-error=[path]

# 查询日志,默认关闭,记录查询的 sql 语句,如果开启会降低 mysql 的整体性能,因为记录日志也是需要消耗系统资源的
log=

4、数据文件

  • frm 文件:存放表结构
  • myd 文件:存放表数据
  • myi 文件:存放表索引

mysql 架构

MySQL 可以在多种不同场景中应用并发挥良好作用,主要体现在存储引擎的架构上,插件式的存储引擎架构查询处理其它的系统任务以及数据的存储提取相分离,这种架构可以根据业务的需求和实际需要选择合适的存储引擎

MySQL 架构

5、连接层

最上层是一些客户端和连接服务,包含本地 sock 通信和大多数基于客户端/服务端工具实现的类似于 tcp/ip 的通信。主要完成一些类似于连接处理授权认证及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于 SSL 的安全链接。服务器也会安全接入的每个客户端验证它所具有的操作权限。

6、服务层

第二层架构主要完成大多数的核心服务功能,如 SQL 接口,并完成缓存的查询SQL 的分析和优化部分内置函数的执行。所有跨存储引擎的功能也在这一层实现,如过程、函数等。在该层,服务器会解析查询并创建相应的内部解析树,并对其完成相应的优化,如确定查询表的顺序,是否利用索引等,最后生成相应的执行操作。如果是 select 语句,服务器还会查询内部的缓存。如果缓存空间足够大,这样在解决大量读操作的环境中能够很好的提升系统的性能。

7、引擎层

存储引擎层,存储引擎真正的负责了 MySQL 中数据的存储和提取,服务器通过API存储引擎进行通信。不同的存储引擎具有的功能不同,这样我们可以根据自己的实际需要进行选取

8、存储层

数据存储层,主要是将数据存储在运行于裸设备的文件系统之上,并完成与存储引擎的交互

9、MyISAM 和 InnoDB 引擎对比

对比项 MyISAM InnoDB
主外键 不支持 支持
事务 不支持 支持
行表锁 表锁,即只操作一条记录也会锁住整个表,不适合高并发的操作
适合读的操作
行锁,操作时只锁某一行,不对其它行有影响
适合高并发操作
缓存 只缓存索引,不缓存真实数据 不仅缓存索引,还要缓存真实数据,对内存要求较高,而且内存
大小对性能有决定性的影响
表空间
关注点 性能 事务
默认安装 YES YES

索引优化分析

10、sql 执行慢的原因

10.1、单值索引

1
2
3
4
select * from user where name = '' and email = ''

-- 在 user 表中的 name 字段上建立索引
create index idx_user_name on user(name);

10.2、复合索引

1
2
-- 在 user 表中的 name 和 email 字段上建立索引
create index idx_user_nameEmail on user(name,email);

10.3、关联查询太多 join

10.4、服务器调优及各个参数的设置(缓冲、线程数)

11、常见的通用的 join 查询

11.1、SQL 执行顺序

11.1.1、手写

1
2
3
4
5
6
7
8
9
10
SELECT DISTINCT
<select_list>
FROM
<left_table> <join_type>
JOIN <right_table> On <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>

11.1.2、机读

1
2
3
4
5
6
7
8
9
10
FROM <left_table>
On <join_condition>
<join_type> JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT
DISTINCT <select_list>
ORDER BY <order_by_condition>
LIMIT <limit_number>

11.2、7 中 join

sqljoin_clear

11.2.1、INNER JOIN 内连接

1
2
-- A、B 表的共有
SELECT <select_list> FROM TableA A INNER JOIN TABLE B B ON A.Key = B.Key;

11.2.2、LEFT JOIN 左连接

1
2
-- A 表的独有 加 A、B 表的共有
SELECT <select_list> FROM TableA A LEFT JOIN TableB B ON A.Key = B.Key;

11.2.3、RIGHT JOIN 右连接

1
2
-- B 表的独有 加 A、B 表的共有
SELECT <select_list> FROM TableA A RIGHT JOIN TableB B ON A.Key = B.Key;

11.2.4、左外部连接

1
2
-- A 表的独有
SELECT <select_list> FROM TableA A LEFT JOIN TableB B ON A.Key = B.Key WHERE B.key is NULL;

11.2.5、右外部连接

1
2
-- B 表的独有
SELECT <select_list> FROM TableA A RIGHT JOIN TableB B ON A.Key = B.Key WHERE A.key is NULL;

11.2.6、全连接

1
2
3
4
5
6
7
-- A、B 的合并
-- MySQL 中无法体现
SELECT <select_list> FROM TableA A FULL OUTER JOIN TABLE B B ON A.Key = B.Key;
-- 使用 union
SELECT <select_list> FROM TableA A LEFT JOIN TableB B ON A.Key = B.Key;
union -- 自带去重
SELECT <select_list> FROM TableA A RIGHT JOIN TableB B ON A.Key = B.Key;

11.2.7、全外部连接

1
2
3
4
5
6
7
-- A 的独有 + B 的独有
-- MySQL 中无法体现
SELECT <select_list> FROM TableA A FULL OUTER JOIN TABLE B B ON A.Key = B.Key WHERE A.Key I NULL OR B.Key IS NULL;

SELECT <select_list> FROM TableA A LEFT JOIN TableB B ON A.Key = B.Key WHERE B.key is NULL;
union
SELECT <select_list> FROM TableA A RIGHT JOIN TableB B ON A.Key = B.Key WHERE A.key is NULL;

索引

12、概述

索引(Index):是帮助 MySQL 高效获取数据的数据结构。索引的目的在于提高查询效率,可以类比字典。

索引是一种数据结构。可以理解为 排好序的快速查找数据结构。

索引会影响 where 查询的条件 和 order by 的排序。

数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引(B树)

一般索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上

13、优势

  1. 类似大学图书馆建书目索引,提高数据检索的效率,降低数据库的 IO 成本
  2. 通过索引列对数据进行了排序,降低数据排序的成本,降低了 CPU 的消耗

14、劣势

  1. 实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的
  2. 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行 INSERT、UPDATE 和 DELETE。因为更新表时,MySQL 不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。

15、mysql 索引分类

一张表的索引最好不要超过 5 个

15.1、单值索引

即一个索引只包含单个列,一个表可以有多个单列

15.2、唯一索引

索引列的值必须唯一,但允许有空值

15.3、复合索引

即一个索引包含多个列,复合索引一般优于单值索引

15.4、基本语法

1
2
3
4
5
6
7
8
9
-- 增加
CREATE [UNIQUE] INDEX indexName ON myTable(columnName(length));
ALTER myTable ADD [UNIQUE] INDEX [indexName] ON (columnName(length));

-- 删除
DROP INDEX [indexName] ON myTable;

-- 查看
SHOW INDEX FROM myTable;

16、mysql 索引结构

16.1、BTree 索引

b树索引原理

真实数据存在于叶子节点,即 2、4、8、10、14、17、28、29、40、63、75、79

非叶子节点不存储真实的数据,只存储指引搜索方向的数据项,如16、34 并不真实存在于数据表中。

16.2、Hash 索引

16.3、full-text 全文索引

16.4、R-Tree 索引

17、哪些情况需要创建索引

  1. 逐渐自动建立唯一索引

  2. 频繁作为查询条件的字段应该创建索引

  3. 查询中与其他表关联的字段,外键关系建立索引

  4. 频繁更新的字段不适合创建索引,因为每次更新不单单是更新了记录,还会更新索引

  5. where 条件里用不到的字段不创建索引

  6. 单键/组合索引的选择问题(在高并发下倾向创建组合索引)

  7. 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度

18、哪些情况不需要创建索引

  1. 表的记录太少(三百万左右性能开始下降)

  2. 经常增删改的表

  3. 数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的数据列建立索引(如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果)

    1
    表中不重复的数据/表中总数据 = 索引的选择性,这个值越接近于 1,这个索引的效率就高

查询截取分析

19、MySql Query Optimizer

MySQL 中专门负责优化 SELECT 语句的优化器模块,主要功能:通过计算分析系统中收集到的统计信息,为客户端请求的 Query 提供他认为最优的执行计划。

20、MySQL 常见瓶颈

  1. CPU:CPU 在饱和的时候一般发生在数据装入内存或从磁盘上读取数据的时候
  2. IO:磁盘 I/O 瓶颈发生在装入数据远大于内存容量的时候
  3. 服务器硬件的性能瓶颈:top,free,iostat 和 vmstat 来查看系统的性能状态

21、Explain

能干嘛:

  • 表的读取顺序
  • 数据读取操作的操作类型
  • 哪些索引可以使用
  • 哪些索引被实际使用
  • 表之间的引用
  • 每张表有多少行被优化器查询

怎么用:

Explain + SQL 语句

执行计划包含的信息:

id select_type table type possible_keys key key_len ref rows extra
select 查询的序列号,包含一组数字,
表示查询中执行 select 子句或操作表的顺序
SIMPLE:简单的 select 查询,查询中不包含子查询或者 UNION:
PRIMARY:最外层查询
SUBQUERY:子查询
DERIVED:在 FROM 列表中包含的子查询被标记为 DERIVED(衍生)MySQL会递归这些子查询,把结果放在临时表中
UNION:若第二个 SELECT 出现在 UNION 之后,则被标记为 UNION;若 UNION 包含在 FROM 子句的子查询中,外层 SELECT 将被标记为:DERIVED
UNION RESULT:从 UNION 表获取结果的 SELECT
最好到最差依次是:system>const>eq_ref
>ref>range>index>all
显示可能应用在这张表中的索引,一个或多个。 实际使用的索引,如果为null,则没有使用索引 表示索引中使用的字节数,可通过该列计算查询中使用的索引长度。在不损失精确性的情况下,长度越短越好 显示索引哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值 根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数 包含不适合在其它列中显示但十分重要的额外信息
三种情况:1、id 相同,执行顺序由上至下
2、如果是子查询,id 的序号会递增,
id 值越大优先级越高,越先被执行
3、id 如果相同,可以认为是一组,从上往下顺序
执行,在所有组中,id 值越大,优先级越高,
越先执行
查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询 一般保证查询在range级别或ref级别 查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用 查询中若使用了覆盖索引,则索引只出现在key列表中 key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的

22、索引优化

22.1、单表

  • 范围会导致索引失效,组合索引中的字段不要涉及到范围

22.2、两表

  • LEFT JOIN 建立右表索引,LEFT JOIN 条件用于确定如何从右表搜索行,左边一定都有, 所以右边是关键点,一定要建立索引。(右连接类似)

22.3、三表

  • 索引最好设置在需要经常查询的字段中
  • 尽可能减少 join 语句中的 NestedLoop 的循环总次数:“永远用小结果集驱动大的结果集”
  • 优先优化 Nested Loop 的内层循环
  • 保证 Join 语句中被驱动表上 join 条件字段已经被索引
  • 当无法保证被驱动表的 join 条件字段被索引且内存资源充足的前提下, 不要太吝惜 joinbuffer 的使用

22.4、索引失效

  1. 全值匹配我最爱
  2. 最佳左前缀法则:如果索引了多列,要遵守最佳左前缀法则,指的是查询从索引的最左前列开始(开头大哥不能死)并且不跳过索引中的列(中间兄弟不能断)
  3. 不在索引列上做任何的操作(计算、函数、(自动 or 手动)类型转换),会导致索引失效而转向全表扫描
  4. 存储引擎不能使用索引中范围条件右边的列
  5. 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少 select *
  6. mysql 在使用不等于(!= 或者 <>)的时候无法使用索引会导致全表扫描
  7. is null , is not null 也无法使用索引
  8. like 以通配符开头(‘%abc…)MySQL 索引失效会变成全表扫描的操作(用覆盖索引避免全表扫描)
  9. 字符串不加单引号索引失效
  10. 少用 or,用它连接时会索引失效

22.5、一般性建议

  1. 对于单键索引,尽量选择针对当前 query 过滤性更好的索引
  2. 在选择组合索引的时候,当前 query 中过滤性最好的字段在索引字段顺序中, 位置越靠前越好
  3. 在选择组合索引的时候,尽量选择可以能够包含当前 query 中的 where 字句中更多字段的索引
  4. 尽可能通过分析统计信息和调整 query 的写法来达到选择合适索引的目的

查询优化

23、一般操作

  1. 慢查询的开启并捕获
  2. explain + 慢 sql 分析
  3. show profile 查询 sql 在 mysql 服务器里面的执行细节和生命周期情况
  4. sql 数据库服务器的参数调优

24、优化策略

  1. 永远小表驱动大表
  2. exists or in 的使用,看子查询与主查询谁的数据量更小
  3. order by 关键字优化
    • 尽量使用 index 方式排序,避免使用 filesort 方式排序
      • order by 语句使用索引最左前列
      • 使用 where 子句与 order by 子句条件列组合满足索引最左前列
    • 尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀
    • 如果不在索引列上,filesort 有两种算法:mysql 就要启动双路排序和单路排序
      • 双路排序:取一批数据,要对磁盘进行两次扫描
      • 单路排序:从磁盘中查询需要的所有列,按照 order by 列在 buffer 对它们进行排序,然后扫描顺序后的列表进行输出
    • 尽量不要用 select *
    • 增大 sort_buffer_size 的值
    • 增大 max_length_for_sort_data 的值
  4. group by 关键字优化
    • 基本与 group by 一致

慢查询日志

mysql 的慢查询是 mysql 提供的一种日志记录,它用来记录在 mysql 中响应时间超过阈值的语句,具体指运行时间超过 long_query_time 值的 sql,则会被记录到慢查询日志中

如果不是调休需要,一般不建议启动该参数,会带来一定的性能影响

1
2
3
4
# 设置开启慢查询 或者 修改 my.conf 配置文件
set global slow_query_log = 1;
# 查询日否开启慢查询
show variables like '%slow_query_log%';

MySql 锁机制

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

25、锁的分类

  1. 从对数据的操作类型分:

    • 读锁(共享锁):针对同一份数据,多个读操作可以同时进行而不会互相影响
    • 写锁(排它锁):当前写操作没有完成前,它会阻断其它写锁和读锁
    • 读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞
  2. 从对数据的操作粒度分:

    • 表锁(偏读)

    • 行锁(偏写)

      • 支持事务

        • 更新丢失:最后的更新覆盖了其它事务所做的更新
        • 脏读:事务 A 读取到了 事务 B 已修改但尚未提交的数据
        • 不可重复读:事务 A 读取到了事务 B 已提交过的修改数据
        • 幻读:事务 A 读取到了 事务 B 新增的数据
      • 无索引行锁升级为表锁(varchar 类型要加 单引号

      • 间隙锁

        • 当用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB 会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做 “间隙(GAP)”
        • 危害
          • query 执行过程中通过范围查找的话,会锁定整个范围内所有的索引键值,即使这个键值并不存在
          • 当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定键值范围内的任何数据。在某些场景下这可能会对性能造成很大危害
      • 锁定某一行

        1
        select xxx ... for update 锁定某一行后,其它的操作会被阻塞,知道锁定行的会话提交 commit
    • 优化建议

      • 尽可能让所有数据检索都通过索引来完成,避免无索引行锁升级为表锁
      • 合理设计索引,尽量缩小锁的范围
      • 尽可能较少检索条件,避免间隙锁
      • 尽量控制事务大小,减少锁定资源量和时间长度
      • 尽可能低级别事务隔离

主从复制

26、复制原理

MySQL 复制过程分成三步:

  1. master 将改变记录到二进制日志(binary log),这些记录过程叫做二进制日志事件,binary log events
  2. slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
  3. slave 重做中继日志中的事件,将改变应用到自己的数据库中,MySQL 复制是异步的且串行化的

27、复制的基本原则

  1. 每个 slave 只有一个 master
  2. 每个 slave 只能有一个唯一的服务器 ID
  3. 每个 master 可以有多个 salve

28、最大问题

网络延时

29、常见配置

  1. mysql 版本一致且后台以服务运行

  2. 主从都配置在【mysqlId】结点下,都是小写

  3. 修改配置文件

    1. 主机

      • 主服务器唯一 ID

      • 启用二进制日志

      • 【可选】启用错误日志

      • 【可选】根目录

      • 【可选】临时目录

      • 【可选】数据目录

      • read-only = 0

      • 【可选】设置不要复制的数据库

      • 【可选】设置需要复制的数据库

    2. 从机

      • 从服务器唯一 ID
      • 启用二进制文件
  4. 主机 and 从机 重启 mysql 服务

  • Copyrights © 2022-2023 hqz

请我喝杯咖啡吧~

支付宝
微信