范式化设计
可以近似理解成一张数据表的表结构所符合的某种设计标准的级别
第一范式:
属于第一范式关系的所有属性都不可再分,即数据项不可分;
第二范式:
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF);
第二范式(2NF)要求实体的属性完全依赖于主关键字;
第三范式:
满足第三范式(3NF) 必须先满足第二范式(2NF) ;
第三范式(3NF)要求一个数据库表中不包含已在其它表中包含的非主关键字信息,即数据不能存在传递关系即每个属性都跟主键有直接关系而不是间接关系。
反范式化设计
1、为了性能和读取效率而适当的违反对数据库设计范式的要求; 2、为了查询的性能,允许存在部分 (少量)余数据;
字段数据类型优化
基本原则:
更小的通常更好; 简单就好; 尽量避免NULL;
数据库命名规范
推荐命名规范
可读性原则;
必须使用小写字母或者数字;
不使用复数名词;
禁用保留字;
· 索引命名;
索引是什么
官方定义:索引(Index)是帮助Mysql高校获取数据的数据结构 本质:数据结构 作用:高效获取索引
多叉树
树(Tree)::N个结点构成的有限集合;
树中有一个称为"根(Root)"的特殊结点;
其余结点可分为M个互不相交的树,称为原来结点的子树;
二叉查找树
左子树的所有的值小于根节点的值; 右子树的所有的值大于或等于根节点的值; 左、右子树满足以上两点;
AVL树
AVL树: 平衡二叉树,满足以下属性:
它的左右两个子树的高度差 (平衡因子) 的绝对值不超过1;
左右两个子树都是一棵平衡二叉树; 目的:使得树的高度最低,因为树查找的效率决定于树的高度;
B+树
多叉平衡查找树;
在磁盘设备上,通过B+树可以有效的存储数据;
所有记录都存储在叶子节点上,非叶子(non-leaf)存储索引(keys)信息;而且记录按照索引列的值由小到大排好了序;
B+树含有非常高的扇出(fanout) ,通常超过100,在查找一个记录时,可以有效的减少IO操作; 扇出: 是每个索引节点(Non-LeafPage)指向每个叶子节点(LeafPage)的指针;
扇出数 = 索引节点(Non-LeafPage)可存储的最大关键字个数 + 1;
聚集索引/聚簇索引
将表的主键用来构造一棵B+树,并且将整张表的行记录数据存放在该B+树的叶子节点中;
辅助索引/二级索引
叶子节点除了包含键值以外,每个叶子节点中的索引行中还包含了一个书签( bookmark) (每个索引一颗B+树,不包含行记录的全部数据)
回表
通过辅助索引获得主键,然后再通过主键索 (聚集索引)来找到一个完整的行记录;
联合索引/复合索引
将表上的多个列组合起来进行索引我们称之为联合索引或者复合索引;
覆盖索引
从辅助索引中就可以得到查询的记录,而不需要查询聚集索引中的记录;
B+树的索引总结
聚集索引/聚簇索引--主键 所有的列数据; 辅助索引/二级索引 - 索引列+主键。 查其他的列>>>>>>回表(聚集索引/聚族索引);
联合索引/复合索引--- (多个列<左边开始排序>+ 主键) ->覆盖索引(不是索引); 查询效率B+树的高度,生产B+高度3,4,IO 3、4次;
哈希索引
自适应哈希索引
索引的作用
索引在查询中的作用
1、一个索引就是一个B+树,索引让我们的查询可以快速定位和扫描到我们需要的数据记录上,加快查询的速度。
2、一个select查询语句在执行过程中一般最多能使用一个二级索引,即使在where条件中用了多个二级索引。
高性能的索引创建策略
索引列的类型尽量小
索引列的选择:索引的选择性/离散性:,不重复的索引值和数据表的记录总数 (N)的比值 (范围1/N到1)越高则查询效率越高;
前缀索引
针对blob、text、很长的varchar字段,mysql不支持索引他们的全部长度,需建立前缀索引.语法: Alter table tableName add key/index (column(X))前缀索引的选择(X);
缺点: 无法应用于order by 和 group by,也无法做覆盖索引;
后缀索引
mysql不支持后缀索引;
可以通过在表中添加一个新列,用于保存要被建立后缀索引的字段倒排值,然后建立前缀索引。场景:查询邮箱后缀;
只为搜索、排序或分组的列创建索引
多列索引:
将选择性最高的列放到索引最前列;
根据那些运行频率最高的查询来调整索引列的顺序;
优化性能时,需要使用相同的列但顺序不同的索引来满足不同类型的查询需求;
三星索引
对于一个查询而言,三星索引可能是其最好的索引。
满足的条件如下:
索引将相关的记录放到一起则获得一星;
如果索引中的数据顺序和查找中的排列顺序一致则获得二星(排序星); 如果索引中的列包含了查询中需要的全部列则获得三星 (宽索引星)(优先级最高);
MySQL调优金字塔
硬件和OS调优
MySQL调优
架构调优
查询性能优化
慢查询基础-优化数据访问
请求了不需要的数据?
查询不需要的记录总是取出全部列
重复查询相同的数据
是否在扫描额外的记录?
响应时间
扫描的行数和返回的行数
扫描的行数和访问类型
慢查询
慢查询配置
mysql记录所有执行超过long_query_time参数设定的时间闻值的SQL语句的日志 show variables like 'long query time';set GLOBAL slow query log=5;
慢查询分析工具
执行计划
执行计划的语法:在SQL查询的前面加上EXPLAIN关键字就行。比如: EXPLAIN select* from order_exp;
Id:
查询语句中每出现一个SELECT关键字,MySQL就会为它分配一个唯一的id值。这个id值就是EXPLAIN语句的第一个列;
Table:
EXPLAIN语句输出的每条记录都对应着某个单表的访问方法该条记录的table列代表着该表的表名;
Select_Type:
通过某个小查询的select type属性,就知道了这个小查询在整个大查询中扮演了一个什么角色; SIMPLE: 简单的select 查询,不使用 union 及子查询; PRIMARY: 最外层的 select 查询; UNION:UNION 中的第二个或随后的 select 查询,不 依赖于外部查询的结果集; UNION RESULT: UNION 结果集;
SUBQUERY:子查询中的第一个 select 查询,不依赖于外 部查询的结果集; DEPENDENT UNION: UNION 中的第二个或随后的 select 查询,依赖于外部查询的结果集; DEPENDENT SUBQUERY: 子查询中的第一个 select 查询,依赖于外部查询的结果集; DERIVED: 用于 from 子句里有子查询的情况。 MySQL 会 递归执行这些子查询,把结果放在临时表里;
Partitions:
和分区表有关,一般情况下我们的查询语句的执行计划的partitions列的值都是NULL;
Type:
执行计划的一条记录就代表着MySQL对某个表的执行查询时的访问方法/访问类型,其中的type列就表明了这个访问方法/访问类型是个什么东西,是较为重要的一个指标,结果值从最好到最坏依次是:system > const > eq_ref > ref > fulltext > ref or null > index merge >unique subquery > index subquery > range > index > ALL 出现比较多的system>const>eg_ref>ref>range>index>ALL一般来说,得保证查询至少达到range级别,最好能达到ref。
possible keys与key:
possible_keys列表示在某个查询语句中,对某个表执行单表查询时可能用到的索引有哪些,key列表示实际用到的索引有哪些,如果为NULL,则没有使用索引;
key_len:
key_len列表示当优化器决定使用某个索引执行查询时,该索引记录的最大长度;
ref:
当使用索引列等值匹配的条件去执行查询时,也就是在访问方法是const、eg ref、ref、ref or nullunique sutbquery、index subquery其中之一时,ref列展示的就是与索引列作等值匹配的是谁;
rows:
如果查询优化器决定使用全表扫描的方式对某个表执行查询时,执行计划的rows列就代表预计需要扫描的行数,如果使用索引来执行查询时,执行计划的rows列就代表预计扫描的索引记录行数。
filtered:
查询优化器预测有多少条记录满足其余的搜索条件;
Extra:
Extra列是用来说明一些额外信息的,我们可以通过这些额外信息来更准确的理解MySQL到底将如何执行给定的查询语句。
查询优化器
SQL的处理(MySQL) 缓存 解析查询 优化 (查询优化器)
重写查询
表的读取顺序
选择索引
高性能的索引使用策略
不在索引列上做任何操作
表达式;
函数;
尽量全值匹配
最佳左前缀法则key_len
范围条件放最后
左边的列是精确查找,则右边的列可进行范围查找中间有范围查询会导致后面的列全部失效,无法充分利用联合索引;
覆盖索引尽量用
尽量不要使用*;
不等于要慎用
使用不等于(!= 或者<>)的时候无法使用索引会导致全表扫描;
Null/Not 有影响
字符类型加引号
使用or关键字时要注意
尽量不要使用*;
排序要当心
ASC、DESC别混用排序列包含非同一个索引的列;
尽可能按主键顺序插入行
优化limit分页
优化Count查询
关于Null的特别说明
like查询固定前缀
like 'asd%'
数据库事务
什么是事务
事务特性(ACID)
原子性 (atomicity) 一致性 (consistency) 隔离性 (isolation) 持久性 (durability)
脏读
不可重复读
幻读
事务问题严重程度排名
脏读>不可重复读>幻读
SQL92标准中的隔离级别
READ UNCOMMITTED: 未提交读 READ COMMITTED: 已提交读 REPEATABLE READ:可重复读 SERIALIZABLE: 可串行化
MySQL中的隔离级别
READ UNCOMMITTED: 未提交读 READ COMMITTED: 已提交读 REPEATABLE READ:可重复读 SERIALIZABLE: 可串行化
如何设置事务的隔离级别
我们可以通过下边的语句修改事务的隔离级别:SET [GLOBALISESSION] TRANSACTION ISOLATION LEVEL Ievel;查看隔离级别:SHOW VARIABLES LIKE 'transaction_isolation';
MySQL事务
事务的基本语法
保存点(savepoint)
隐式提交(注意事项)
当我们在一个会话里,一个事务还没提交或者回滚时就又使用START TRANSACTION或者BEGIN语句开启了另一个事务时,会隐式的提交上一个事务;
MVCC
版本链
INSERT INTO teacher VALUES(1,李瑾,VM系列);
ReadView(读视图)
m_ids(活跃事务ID列表)
min_trx_id(最小事务ID) max_trx_id(最大事务ID) creator_trx_id(创建的事务ID)
从上边的描述中我们可以看出来,所谓的MVCC (Multi-Version Concurrency Control,多版本并发控制)指的就是在使用READ COMMITTD、REPEATABLE READ这两种隔离级别的事务在执行普通的SELECT操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。READ COMMITTD、REPEATABLE READ这两个隔离级别的一个很大不同就是: 生成ReadView的时机不同,READ COMMITTD在每一次进行普通SELECT操作前都会生成一个ReadView,而REPEATABLE READ只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复使用这个ReadView就好了,从而基本上可以避免幻读现象 (就是第一次读如果ReadView是空的情况中的某些情况则避免不了)
MySQL中的锁
锁:解决问题:事务并发---MVCC 快照
解决事务并发问题
方案一: 读操作MVCC,写操作进行加锁
方案二:读、写操作都采用加锁的方式
锁定读
共享锁和独占锁 共享锁: Shared Locks,简称S锁 select * from table lock in share mode; 独占锁: Exclusive Locks,简称X锁 select * from table for update;
锁定读的SELECT语句。
写操作的锁
锁的粒度
行锁
表锁
表锁与行锁的比较
锁定粒度: 锁 >行锁
加锁效率:表锁 >行锁
冲突概率: 表锁 >行锁
并发性能: 表锁< 行锁
MySQL中的 行锁,表锁
存储引擎有关。非InnoDB 都是表锁; 加在一个表级别,表同时一时刻许一个会话对表进行写操作;
表级别的 S锁: X锁: 元数据锁:alter drop table DDL语句。过程---事务 select update insert 阻塞; IS锁: IX锁: AUTO-INC锁:0是表级别锁、1是轻量锁、2是混合锁
行级别的
索引上加 才是行锁,不是表锁。 索引加锁,执行计划当中:,确定真正使用了索引 加行锁;
间隙锁
死锁:
(试图获得锁时发现死锁;尝试重新启动事务)
设置查看死锁关键参数;show engine innodb status\G 查看死锁信息;
MySQL8新特性
账户与安全
用户创建和授权: 5.7版本grant all privileges on *.* to 'yjx' @'%' identified by'yjx@2022'; 8.0版本create user 'yjx' @'%' identified by 'yjx@2022';grant all privileges on *.* to 'yjx' @'%'; select user, host from mysql.user;
认证插件更新 show variables like 'default_authentication%'
密码管理 修改密码与历史重复最多三次(不需要重启):alter user 'yjx' @'%' password history 3; 修改密码与历史重复最多三次(需要重启):set persist password history=3;
角色管理
索引增强
隐藏索引 创建索引时结尾添加invisible关键字; 不会被优化器使用,不可见索引。 软删除 (老版本 index 删除 (误删) ->创建 都会性能,变成隐藏索引。。。过段时间,彻底删)
灰度发布(线上测试,加隐藏,索引、删除) 通过一些设置 在查询优化器 执行SQL,把索引生效(针对你的测试)发现这个索引没问题,改成正式的索引,生产环境生效; show index from t1\G set session optimizer_switch='use_invisible_indexes=on' alter table tl alter index j_idx invisible;--不可见
降序索引 create table t2(c1 int,c2 int,index idx1(c1 asc,c2 desc)); explain select from t2 order by c1,c2 desc;
函数索引
通用表表达式
通用表 表达式 CTE common table expression with子句
窗口函数
原子DDL操作
drop、crate,、alter;
JSON增强
InnoDB其他改进功能
自增列持久化
MySQL 5.7 以及早期版本,InnoDB 自增列计数器 (AUTO INCREMENT) 的值只存储在内存中。MySQL 8.0每次变化时将自增计数器的最大值写入 redo log,同时在每次检查点将其写入引擎私有的系统表。解决了长期以来的自增字段值可能重复的 bug。
死锁检查控制
MySQL 8.0 (MySQL 5.7.15) 增加了一个新的动态变量,用于控制系统是否执行 nnoDB 死锁检查。对于高并发的系统,禁用死锁检查可能带来性能的提高。innodb_deadlock_detect。
锁定语句选项
SELECT ... FOR SHARE和 SELECT ... FOR UPDATE 中支持 NOWAIT、SKIP LOCKED 选项对于 NOWAIT如果请求的行被其他事务锁定时,语句立即返回。对于 SKIP LOCKED,从返回的结果集中移除被锁定的行。
InnoDB 其他改进功能
支持部分快速 DDL,ALTER TABLE ALGORITHM=INSTANT。 InnoDB 临时表使用共享的临时表空间 ibtmp1。 新增静态变量 innodb_dedicated_server,自动配置InnoDB内存参数:innodb_buffer_pool size/innodb_log_file_size等。 默认创建 2个 UNDO 表空间,不再使用系统表空间。 支持 ALTER TABLESPACE ... RENAME TO 重命名通用表空间。
MySQL体系架构
Drizzle
MariaDB
PerconaiServer
MySQL的替代
Postgre SQL(PG)
SQLite
连接层
Server层
存储引擎
MySQL官方引擎 InnoDB、MyISAM、Archive、Blackhole、CSV、Ferderated、Memory、NDB集群引擎;
第三方引擎
Percona的 XtraDB存储引擎、TokuDB引擎、Infobright、其他;
表引擎的转换
有很多种方法可以将表的存储引擎转换成另外一种引擎,每种方法都有其优点和缺点。常用的有三种方法:
ALTER TABLE
将表从一个引擎修改为另一个引擎最简单的办法是使用ALTER TABLE 语句。下面的语句将mytable的引擎修改为InnoDB :ALTER TABLE mytable ENGINE = InnoDB;
上述语法可以适用任何存储引擎。但需要执行很长时间,在实现上,MySQL会按行将数据从原表复制到一张新的表中,在复制期间可能会消耗系统所有的I/O能力,同时原表上会加上读锁。所以,在繁忙的表上执行此操作要特别小心。
导出与导入
还可以使用mysqldump工具将数据导出到文件,然后修改文件中CREATE TABLE语句的存储引擎选项,注意同时修改表名,因为同一个数据库中不能存在相同的表名,即使它们使用的是不同的存储引擎。
CREATE和 SELECT
先创建一个新的存储引擎的表,然后利用INSERT...SELECT语法来导数据:
CREATE TABLE innodb table LIKE myisam table; ALTER TABLE innodb table ENGINE=InnoDB; INSERT INTO innodb table SELECT * FROM myisam table;
如果数据量很大,则可以考虑做分批处理,针对每一段数据执行事务提交操作。
MyISAM和InnoDB比较
show ENGINES;查看支持的存储引擎;
show variables like '%storage_engine%';查看默认的存储引擎
show databases ;查看数据库
常见的日志文件
1、错误日志
2、慢查询日志
3、普通查询日志(查询日志) 默认关闭
4、二进制文件 (binlog) 除了select之外的 语句 DDL DML,事件形式记录。
单表访问之索引合并
MySQL在一般情况下执行一个查询时最多只会用到单个二级索引,但存在有特殊情况,在这些特殊情况下也可能在一个查询中使用到多个二级索引,MySQL中这种使用到多个索引来完成一次查询的执行方法称之为: 索引合并/index merge;
Intersection合井
1、根据不同的搜索条件读取到不同的二级索引 2、从2个二级索引中得到主键 (id) 的交集
3、最后根据主键ID,进行回表操作
只读取一个二级索引的步骤
1、按照某个条件读取到一个二级索引 2、根据二级索引得到主键ID的值,进行回表操作 3、最后在过滤其他的查询条件
最好是使用联合索引代替索引合并;
连接查询
内连接与外连接
左外连接
SELECT * FROMe1 LEFI [OUTER]JOIN e2 ON 连接条件[WHERE 普通过滤条件];
右外连接 SELECT * FROM e1 RIGHT [OUTER]JOIN e2 0N 连接条件[WHERE 普通过滤条件];
内连接
Select * from e1, e2
Select * from e1join e2; Select * from e1 inner join e2;
Select * from e1 cross join e2;
嵌套循环连接 (Nested-LoopJoin)
for each row in e1 #此处表示遍历满足对e1单表查询结果集中的每一条记录 for each row in e2#此处表示对于某条e1表的记录来说,遍历满足对e2单表查询结果集中的每一条记录 for each row in e3#此处表示对于某条e1和e2表的记录组合来说,对t3表进行单表查询 if row satisfies join conditions, send to client
MySQL对连接的执行
使用索引加快连接速度
基于块的嵌套循环连接 (Block Nested-Loop Join)
MySQL的查询成本计算
什么是成本?
。I/0成本(1.0)
。CPU成本(0.2)
单表查询的成本
基于成本的优化步骤
1、根据搜索条件,找出所有可能使用的索引
2、计算全表扫描的代价
3、计算使用不同索引执行查询的代价
4、对比各种执行方案的代价,找出成本最低的那一个
Explain与查询成本
EXPLAIN输出成本
Optimizer Trace
连接查询成本
两表连接的成本分析 。使用s1作为驱动表的情况 。使用s2作为驱动表的情况
EXPLAIN输出连接成本
多表连接的成本分析
调节成本常数
InnoDB引擎底层解析
InnoDB的三大特性: 双写机制 Buffer Pool 自适应Hash索引
InnoDB的存储结构
有缘更新。。。