目录
1 MySql基础知识
2 MySql逻辑架构
3 并发控制
4 事务
5 MVCC多版本并发控制
6 存储引擎
7 索引
8 MySql优化
9 其他知识点
10 常见问题总结参考资料
· 《高性能MySql》
· 《尚硅谷MySql》
· JavaG
1 MySql基础知识
1.1 数据库的概念
(1)DB
数据库(database):存储数据的“仓库”。它保存了一系列有组织的数据。
(2)DBMS
数据库管理系统(Database Management System)。数据库是通过DBMS创建和操作的容器
(3)SQL
结构化查询语言(Structure Query Language):专门用来与数据库通信的语言
1.2 SQL语言分类
1.2.1 DML(Data Manipulation Language)
数据操纵语句,用于添加、删除、修改、查询数据库记录,并检查数据完整性
(1)INSERT:添加数据到数据库中
(2)UPDATE:修改数据库中的数据
(3)DELETE:删除数据库中的数据
(4)SELECT:选择(查询)数据
1.2.2 DDL(Data Definition Language)
数据定义语句,用于库和表的创建、修改、删除。
(1)CREATE TABLE:创建数据库表
(2)ALTER TABLE:更改表结构、添加、删除、修改列长度
(3)DROP TABLE:删除表
(4)CREATE INDEX:在表上建立索引
(5)DROP INDEX:删除索引
1.2.3 DCL(Data Control Language)
数据控制语句,用于定义用户的访问权限和安全级别。
(1)GRANT:授予访问权限
(2)REVOKE:撤销访问权限
(3)COMMIT:提交事务处理
(4)ROLLBACK:事务处理回退
(5)SAVEPOINT:设置保存点
(6)LOCK:对数据库的特定部分进行锁定
1.3 SQL语言规范
(1)不区分大小写
(2)每句话用;或\g结尾
(3)各子句一般分行写
(4)关键字不能缩写也不能分行
(5)用缩进提高语句的可读性
1.4 数据处理之查询
1.4.1 基本的SELECT语句
(1)别名
- 紧跟列名
- 也可以在列名和别名之间加入关键字‘AS’,别名使用双引号,以便在别名中包含空格或特殊的字符并区分大小写。
(2)字符串
- 字符串可以是 SELECT 列表中的一个字符,数字,日期。
- 日期和字符只能在单引号中出现。
- 每当返回一行时,字符串被输出一次。
1.4.2 过滤和排序数据
(1)过滤
使用WHERE 子句,将不满足条件的行过滤掉。
WHERE 子句紧随 FROM 子句。
(2)where子句中的比较运算
(3)排序 ORDER BY子句
使用 ORDER BY 子句排序
ASC(ascend): 升序
DESC(descend): 降序ORDER BY 子句在SELECT语句的结尾。
- 多个列排序时,按照ORDER BY 列表的顺序排序
1.4.3 分组函数
(1)作用
分组函数作用于一组数据,并对一组数据返回一个值。
(2)组函数类型
AVG() 平均值
COUNT() 计数,记录符合某条件的记录个数
MAX() 最大值
MIN() 最小值
SUM() 求和
(3)组函数类型语法
非法使用组函数
• 不能在 WHERE 子句中使用组函数。
• 可以在 HAVING 子句中使用组函数
(4)分组数据: GROUP BY 子句
- 可以使用GROUP BY子句将表中的数据分成若干组。
- 在SELECT 列表中所有未包含在组函数中的列都应该包含在 GROUP BY 子句中。
- 包含在 GROUP BY 子句中的列不必包含在SELECT 列表中
- 可以使用多个列同时分组
(5)过滤分组: HAVING 子句
使用 HAVING 过滤分组:
行已经被分组。
使用了组函数。
满足HAVING 子句中条件的分组将被显示
1.4.4 多表查询
(1)where链接
连接 n个表,至少需要 n-1个连接条件。 例如:连接三个表,至少需要两个连接条件。
(2)ON子句连接
• 自然连接中是以具有相同名字的列为连接条件的。
• 可以使用 ON 子句指定额外的连接条件。
• 这个连接条件是与其它条件分开的。
• ON 子句使语句具有更高的易读性。
(3)Join子句连接
- 分类:
mysql内连接 [inner] join on
外连接
左外连接 left [outer] join on
右外连接 right [outer] join on
- 图解:
1.4.5 分页查询
1.5 常见函数
1.5.1 字符函数
(1)大小写控制函数
(2)字符控制函数
1.5.2 数学函数
1.5.3 日期函数
1.5.4 流程控制函数【补充】
1.6 子查询
描述子查询可以解决的问题。
• 定义子查询。
• 列出子查询的类型。
• 书写单行子查询和多行子查询。
1.6.1 概念
(1)出现在其他语句内部的select语句,称为子查询或内查询
内部嵌套其他select语句的查询,称为外查询或主查询
示例:
select first_name from employees where
department_id in(
select department_id from departments
where location_id=1700
)
(2)注意事项
- 子查询要包含在括号内。
- 将子查询放在比较条件的右侧。
- 单行操作符对应单行子查询,多行操作符对应多行子查询。
(3)解决的问题
1.6.2 子查询类型
(1)单行子查询
-
语法
- 可以使用组函数、HAVING子句
- 对于子查询中的空值,不返回任何行
(2)多行子查询
-
ANY
-
ALL
1.7 数据处理之增删改
(1)插入数据
-
插入空值
-
插入指定的值
-
从其他表中拷贝数据
(2)更新数据
(3)删除数据
1.8 创建和管理表
- 创建数据库
- 创建表
- 描述各种数据类型
- 修改表的定义
- 删除,重命名和清空表
1.8.1 创建数据库
(1)命名规则
(2)语句
1.8.2 创建表
(1)常用数据类型
(2)使用子查询创建表
(3)ALTER TABLE 语句
-
追加一个新列
-
修改一个列
-
删除一个列
-
重命名一个列
(4)删除表
(5)清空表
(6)改变对象的名称
1.9 约束和分页
- 描述约束
- 创建和维护约束
- 数据库分页
1.9.1 约束
(1)什么是约束
- 为了保证数据的一致性和完整性,SQL规范以约束的方式对表数据进行额外的条件限制。
- 约束是表级的强制规定
- 可以在创建表时规定约束(通过 CREATETABLE 语句),或者在表创建之后也可以(通
过 ALTER TABLE 语句)
(2)约束分类
- 根据约束数据列的限制,约束可分为:
单列约束:每个约束只约束一列
多列约束:每个约束可约束多列数据 - 根据约束的作用范围,约束可分为:
列级约束只能作用在一个列上,跟在列的定义后面
表级约束可以作用在多个列上,不与列一起,而是单独定义
1. NOT NULL约束
- 非空约束用于确保当前列的值不为空值,非空约束只能出现在表对象的列上。
-
Null类型特征:
所有的类型的值都可以是null,包括int、float等数据类型
空字符串””不等于null,0也不等于null
2. UNIQUE约束
- 唯一约束,允许出现多个空值:NULL
- 同一个表可以有多个唯一约束,多个列组合的约束。在创建唯一约束的时候,如果不给唯一约束名称,就
默认和列名相同。 -
MySQL会给唯一约束的列上默认创建一个唯一索引
3. PRIMARY KEY约束
- 主键约束相当于唯一约束+非空约束的组合,主键约束列不允许重复,也不允许出现空值
- 如果是多列组合的主键约束,那么这些列都不允许为空值,并且组合的值不允许重复。
- 每个表最多只允许一个主键,建立主键约束可以在列级别创建,也可以在表级别上创建。
-
MySQL的主键名总是PRIMARY,当创建主键约束时,系统默认会在所在的列和列组合上建立对应的
唯一索引。
4. FOREIGN KEY约束
- 外键约束是保证一个或两个表之间的参照完整性,外键是构建于一个表的两个字段或是两个表的两个字段之间的参照关系。
- 从表的外键值必须在主表中能找到或者为空。当主表的记录被从表参照时,主表的记录将不允许删除,如果要删除数据,需要先删除从表中依赖该记录的数据,然后才可以删除主表的数据。
- 还有一种就是级联删除子表数据。
- 注意:外键约束的参照列,在主表中引用的只能是主键或唯一键约束的列
-
同一个表可以有多个外键约束
5. CHECK约束
1.9.2 分页
(1)limit分页
- 背景
查询返回的记录太多了,查看起来很不方便,怎么样能够实现分页查询呢? - 分页原理
所谓分页显示,就是将数据库中的结果集,一段一段显示出来需要的条件
(2)分页实现
1.10 事物
- 事务的概念和特性
- 事务的隔离级别
- 事务的案例演示
1.10.1 简介
(1)概念
事务由单独单元的一个或多个SQL语句组成,在这个单元中,每个MySQL语句是相互依赖的。而整个单独单元作为一个不可分割的整体,如果单元中某条SQL语句一旦执行失败或产生错误,整个单元将会回滚。所有受到影响的数据将返回到事物开始以前的状态;如果单元中的所有SQL语句均执行成功,则事物被顺利执行。
(2)存储引擎和事物
- 通过show engines;来查看mysql支持的存储引擎。
- 在mysql中用的最多的存储引擎有:innodb,myisam ,memory 等。其中innodb支持事务,而myisam、memory等不支持事务
1.10.2 事物的特点
事务的ACID(acid)属性
- 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 - 一致性(Consistency)
事务必须使数据库从一个一致性状态变换到另外一个一致性状态 - 隔离性(Isolation)
事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。 - 持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响
1.10.3 事物的使用
- 以第一个 DML 语句的执行作为开始
- 以下面的其中之一作为结束:
COMMIT 或 ROLLBACK 语句
DDL 或 DCL 语句(自动提交)
用户会话正常结束
系统异常终了
1.10.4 数据库的隔离级别
(1)事物与事物
- 对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没有采取必要的隔离机制, 就会导致各种并发问题:
脏读: 对于两个事务 T1, T2, T1 读取了已经被 T2 更新但还没有被提交的字段.
之后, 若 T2 回滚, T1读取的内容就是临时且无效的.
不可重复读: 对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段.
之后, T1再次读取同一个字段, 值就不同了.
幻读: 对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插 入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行.
- 数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题.
- 一个事务与其他事务隔离的程度称为隔离级别. 数据库规定了多种事务隔离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就越好, 但并发性越弱.
(2)数据库的隔离级别
(3)设置隔离级别
- 每启动一个 mysql 程序, 就会获得一个单独的数据库连接. 每个数据库连接都有一个全局变量 @@tx_isolation, 表示当前的事务隔离级别.
- 查看当前的隔离级别: ·SELECT @@tx_isolation·;
- 设置当前 mySQL 连接的隔离级别:
set transaction isolation level read committed;
- 设置数据库系统的全局的隔离级别:
set global transaction isolation level read committed;
1.11 视图
- 什么是视图
- 创建或修改视图
- 删除视图
- 查看视图
1.11.1 概念
(1)什么是视图
(2)视图的好处
- 重用sql语句
- 简化复杂的sql操作,不必知道它的查询细节
- 保护数据,提高安全性
1.11.2 操作视图
(1) 创建和修改
视图的可更新性和视图中查询的定义有关系,以下类型的视图是不能更新的。
- 包含以下关键字的sql语句:
分组函数、distinct、group by、having、union或者union all
- 常量视图
- Select中包含子查询
- join
- from一个不能更新的视图
- where子句的子查询引用了from子句中的表
(2) 删除视图
(3) 查看视图
1.12 存储过程和函数
- 什么是存储过程和函数
- 使用存储过程和函数的好处
- 创建存储过程和函数
- 修改存储过程和函数
- 调用存储过程和函数
- 查看存储过程和函数
1.12.1 什么是存储过程和函数
- 存储过程和函数:
事先经过编译并存储在数据库中的一段sql语句的集合。 - 使用好处:
简化应用开发人员的很多工作
减少数据在数据库和应用服务器之间的传输
提高了数据处理的效率
1.12.2 创建存储过程和函数
1.12.3 修改、删除、查看存储过程和函数
1.12.4 调用存储过程和函数
-
举例使用场景:
1.12 流程控制
(1)case结构——作为表达式
(2)case结构——作为独立的语句
(3)循环结构
1.13 Sql语句训练
均来自于leetcode
1.13.1 leetcode595
1.13.2 leetcode627
1.13.3 leetcode620
1.13.4 leetcode596
1.13.5 leetcode182
1.13.6 leetcode196
1.13.7 leetcode175
1.13.8 leetcode181
1.13.9 leetcode183
1.13.10 leetcode184
1.13.11 leetcode176
1.13.12 leetcode177
1.13.13 leetcode178
1.13.14 leetcode180
1.13.15 leetcode626
2 MySql逻辑架构
2.1 架构图
2.2 连接/线程管理
(1)每个客户端连接都会在服务器进程中拥有一个线程
(2)数据库连接池
- 池化思想:预设资源
- 本质是socket连接
- 作用:维护连接的缓存,以便将来重用连接
(3)默认端口号:3306
2.3 关系型数据库
(1)关系型数据库
关系型数据库是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据。简单说,关系型数据库是由多张能互相连接的表组成的数据库。
·优点
- 都是使用表结构,格式一致,易于维护。
- 使用通用的 SQL 语言操作,使用方便,可用于复杂查询。
- 数据存储在磁盘中,安全。
·缺点
- 读写性能比较差,不能满足海量数据的高效率读写。
- 不节省空间。因为建立在关系模型上,就要遵循某些规则,比如数据中某字段值即使为空仍要分配空间。
- 固定的表结构,灵活度较低。
- 常见的关系型数据库有 Oracle、DB2、PostgreSQL、Microsoft SQL Server、Microsoft Access 和 MySQL 等。
(2)非关系型数据库
非关系型数据库又被称为 NoSQL(Not Only SQL ),意为不仅仅是 SQL。通常指数据以对象的形式存储在数据库中,而对象之间的关系通过每个对象自身的属性来决定。
- 优点
- 非关系型数据库存储数据的格式可以是 key-value 形式、文档形式、图片形式等。使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
- 速度快,效率高。NoSQL 可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘。
- 海量数据的维护和处理非常轻松。
- 非关系型数据库具有扩展简单、高并发、高稳定性、成本低廉的优势。
- 可以实现数据的分布式处理。
- 缺点
- 非关系型数据库暂时不提供 SQL 支持,学习和使用成本较高。
- 非关系数据库没有事务处理,没有保证数据的完整性和安全性。适合处理海量数据,但是不一定安全。
- 功能没有关系型数据库完善。
- 常见的非关系型数据库有 Neo4j、MongoDB、Redis、Memcached、MemcacheDB 和 HBase 等。
-
分类
- 共同的特点
- 易扩展
NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。无形之间,在架构的层面上带来了可扩展的能力。 [2] - 数据量,高性能
NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。这得益于它的无关系性,数据库的结构简单。一般MySQL使用Query Cache。NoSQL的Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说性能就要高很多。 [2] - 灵活的数据模型
NoSQL无须事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是——个噩梦。这点在大数据量的Web 2.0时代尤其明显。 [2] - 高可用
NoSQL在不太影响性能的情况,就可以方便地实现高可用的架构。比如Cassandra、HBase模型,通过复制模型也能实现高可用。
- 易扩展
2.4 查询缓存
(1)执行查询语句时,先查询缓存
(2)MySql8.0后移除,不太实用,可通过redis等高速缓存缓存结果。
(3)弊端:
- 额外的开销,查询后缓存,失效后销毁。
- 严格匹配才能命中缓存
- 查询中不能包含不确定语句,否则不缓存
2.5 存储引擎
- 作用:负责MySql中数据的存储和提取
- 服务器通过API与存储引擎通信
3 并发控制
3.1 读写锁
(1)共享锁--读锁
多个客户在同一时刻可以同时读取同一个资源,互不干扰。
(2)排他锁--写锁
- 一个写锁会阻塞其他的写锁和读锁
- 写锁比读锁有更高的优先级
3.2 锁粒度
尽量只锁定需要修改的部分数据,而不是所有的资源。MySQL存储引擎可以实现自己的锁策略和锁粒度。
3.2.1 表锁
特点:
- 锁定整张表
- 不会出现死锁
- 开销小
- MySql为DDL类语句使用标所,忽略存储引擎的锁机制。
3.2.2 行锁
3.2.2.1 特点
- 锁定当前操作的行
- 最大程度地支持并发处理
- 开销大
- 会出现死锁
3.2.2.2 InnoDB中的行锁分类
- Record lock 对索引加锁,锁定行
- Gap lock “间隙”加锁,锁定一个范围(不含索引项本身),防止幻读
- Next-Key lock 结合上述两种,锁定索引项本身和索引范围,解决幻读问题
3.3 InnoDB的死锁
(1)InnoDB的行级锁是基于索引实现的,如果查询语句为命中任何索引,那么InnoDB会使用表级锁
(2)使用锁的时候,如果表没有定义任何索引,那么InnoDB会创建一个隐藏的聚簇索引并使用这个索引来加记录锁。
(3)InnoDB产生死锁原因
不同于MyISAM总是一次性获得所需的全部锁,InnoDB的锁是逐步获得的,当两个事务都需要获得对方持有的锁,导致双方都在等待,这就产生了死锁。
发生死锁后,InnoDB一般都可以检测到,并使一个事务释放锁回退(InnoDB目前将持有最少行级排他锁的事务回滚),另一个则可以获取锁完成事务
(4)避免死锁:
- 通过表级锁来减少死锁产生的概率;
- 多个程序尽量约定以相同的顺序访问表(这也是解决并发理论中哲学家就餐问题的一种思路);
同一个事务尽可能做到一次锁定所需要的所有资源。
4 事务
4.1 概念
逻辑上的一组操作,要么都执行,要么都不执行(即回滚,返回上一次正确状态)。
4.2 事务四大特性(ACID)
(1)原子性
事务是最小的执行单位,不可分割。整个事务中的所有操作要么都提交成功,要么全部失败回滚。
(2)一致性
执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的。若事务最终没有提交,则事务中所做的修改不会保存到数据库中。
(3)隔离性
并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库的数据是独立的。
四种隔离级别
- READ UNCOMMITTED 未提交读/脏读。事务中的修改还没有提交,对其他事务也可见,即其他事务读取了未提交的数据。
- READ COMMITTED 提交读/不可重复读。一个事务只能“看见”已经提交的事务所做的修改,可能执行两次查询,等到不一样的结果。
- REPEATABLE READ 可重复读/幻读。是MySQL的默认事务隔离级别,保证了在同一个事务中多次读取同样记录的结果一致。可能发生幻读:一个事务在读取某个范围内的记录时,另一个事务在范围内插入记录,导致幻行。通过MVCC多版本并发控制解决问题。
- SERIALIZEABLE 可串行化。最高的隔离级别,强制事务串行执行。本质是在读取的每一行数据上都加锁。
(4)持久性
一旦事务提交,则其所做的修改就会永久保存到数据库中。
4.3 事务日志
- 存储引擎在修改表的数据是只需要修改其内存的拷贝,再把修改行为记录到持久在硬盘的事务日志中。
- 即修改数据,需要写两次磁盘。
- 若系统崩溃,可通过日志自动恢复数据
4.4 MySQL中的事务
(1)MySQL默认采用自动提交模式。即如果不显式地开始一个事务,则每个查询都被当做一个事务执行提交操作。
(2)显式和隐式锁定
- 隐式:事务执行过程中,随时都可以执行锁定,锁只有在执行COMMIT或者ROLLBACK的时候才会释放锁
- 显式:在MySQL语句中使用LOCK TABLES或者UNLOCK TABLES。
5 MVCC多版本并发控制
5.1 特性
MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然不同数据库的实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。
MVCC在MySQL InnoDB中的实现主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读
5.2 相关概念
5.2.1 快照 snapshot
(1)事务快照是用来存储数据库的事务运行情况
(2)生成时机
- 在innodb中(默认repeatable read级别), 事务在begin/start transaction之后的第一条select读操作后, 会创建一个快照(read view), 将当前系统中活跃的其他事务记录记录起来;
- 在innodb中(READ COMMITTED级别), 事务中每条select语句都会创建一个快照(read view);
5.2.2 undo-log
(1)当我们对记录做了变更操作时就会产生undo记录
(2)Undo记录中存储的是老版本数据。当一个旧的事务需要读取数据时,为了能读取到老版本的数据,需要顺着undo链找到满足其可见性的记录
5.2.3 redo-log
存储变更后的数据
5.3 InnoDB实现的MVCC
5.3.1 InnoDB存储引擎在数据库每行数据的后面添加了三个字段
字段称之为系统版本号。
(1) 事务ID DB_TRX_ID
用来标识最近一次对本行记录做修改(insert|update)的事务的标识符, 即最后一次修改(insert|update)本行记录的事务id。
至于delete操作,在innodb看来也不过是一次update操作,更新行中的一个特殊位将行表示为deleted, 并非真正删除。
(2)回滚指针 DB_ROLL_PTR
指写入回滚段(rollback segment)的 undo log record (撤销日志记录记录)。 如果一行记录被更新, 则 undo log record 包含 '重建该行记录被更新之前内容' 所必须的信息
(3) 新行插入而单调递增的ID DB_ROW_ID
如果我们的表中没有主键或合适的唯一索引, 也就是无法生成聚簇索引的时候, InnoDB会帮我们自动生成聚集索引, 但聚簇索引会使用DB_ROW_ID的值来作为主键; 如果我们有自己的主键或者合适的唯一索引, 那么聚簇索引中也就不会包含 DB_ROW_ID 了
5.3.2 更新步骤
(1)排他锁锁定该行
(2)记录redo-log
(3)将修改前的值复制到undo-log
(4)修改当前行的值,填写事务编号,使用回滚指针,指向Undo-log中的修改前的行
5.3.3 当前读和快照读
InnoDB存储引擎默认的事务隔离级别是REPEATABLE-READ。通过 "行排他锁+MVCC" 一起实现的, 不仅可以保证可重复读, 还可以防止幻读。
(1)当前读
如select ... lock in share mode, select ... for update ,insert,update,delete操作,在RR级别下,使用record lock 和 gap lock来实现的。
(2)快照读
如简单的select操作(当然不包括 select ... lock in share mode, select ... for update),是通过MVVC(多版本控制)和undo log来实现的。
- REPEATABLE-READ 此时在第一次读操作时,生成Read View数据(快照),所以可以重复读取,MVCC的活跃事务列表记录后面所有事务,所以可以读到历史版本数据。
- READ COMMITTED 每次读取数据前都生成一个ReadView ,所以不能重复读取,MVCC的活跃事务列表记录此时后面的未提交的事务,只能读到新版本的数据。
参考:MVCC到底是什么?这一篇博客就够啦_flying_hengfei的博客-CSDN博客_mvcc作用
Mysql 间隙锁原理,以及Repeatable Read隔离级别下可以防止幻读原理(百度) - aspirant - 博客园
【MySQL】当前读、快照读、MVCC - wwcom123 - 博客园
5.3.4 工作环境
仅在两个隔离级别下工作,REPEATABLE READ(可重复读)和READ COMMITTED(提交读)。
6 存储引擎
6.1 查看表的存储引擎
show table status like "table_name"
6.2 MyISAM和InnoDB对比
MySQL 5.5版本后默认的存储引擎为InnoDB。
(1)锁机制
MyISAM只有表级锁,InnoDB支持行级锁(默认)和表级锁。
(2)事务
MyISAM不支持事务,InnoDB事务安全
(3)查询和添加速度
MyISAM每次查询具有原子性,执行速度比InnoDB快。
(4)外键
MyISAM不支持,而InnoDB支持
主键和外键参考:(转)关于数据库主键和外键(终于弄懂啦) - liuslayer - 博客园
(5)MVCC
MyISAM不支持,而InnoDB支持
(6)索引
MyISAM的叶节点是数据记录的地址,即为“非聚集索引”。
-
InnoDB叶节点是完整的数据记录,即为“聚集索引”,索引的Key为数据表的主键。所以InnoDB表数据文件本身就是主索引,其余索引都是辅助索引,data中记录了主键的值而不是地址。
因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,则MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。
聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。
聚集索引参考:聚集索引和非聚集索引(整理) - 布颜书 - 博客园
· 注意
“聚集索引”是一种数据存储方式,同时保存索引和数据行。一个表中只能有一个聚集索引。
7 索引
7.1 意义
索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。
7.2 实现原理
7.2.1 B-Tree索引
(1)按顺序存储值,每一个叶子节点到根距离相同。
(2)B+Tree:叶节点指向下一个叶节点,方便叶节点遍历
7.2.2 哈希索引
(1)基于哈希表实现,存储引擎会对所有的索引列计算一个哈希码
(2)在为单条记录查询时,选择哈希更快
(3)自适应哈希索引(InnoDB):当索引值被使用非常频繁时,基于B-Tree索引上再建一个哈希索引。
(4)避免哈希冲突:在WHERE条件中带入哈希值和对应列值。
7.3 分类
(1)主键索引
- 唯一性索引,必须指定为“PRIMARY KEY”。每个表只能有一个主键,主键也不能为空
- 方式:
· CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) )
· ALTER TABLE tablename ADD PRIMARY KEY (列的列表)
(2)全文索引
- FULLTEXT (title,body),查找的是文本中的关键词
select * from articles where **match(title,body) against ( 'database')**
(3)普通索引
- 普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度
- create index 索引名 on 表 (列1,列名2);
(4)唯一 索引
- 索引列的所有值都只能出现一次,即必须唯一。
- CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表)
(5)组合索引
普通索引和组合索引 -
关于辅助索引的执行流程
MySQL的数据结构以及辅助索引的使用_MemoForward的博客-CSDN博客_mysql辅助索引关于覆盖索引
什么是覆盖索引?如何利用覆盖索引进行SQL语句优化?斜阳雨陌-CSDN博客覆盖索引
为什么覆盖索引可以加快查询
注意区别
- 主键创建后一定包含一个唯一性索引,唯一性索引并不一定就是主键。
- 唯一性索引列允许空值,而主键列不允许为空值。
- 主键列在创建时,已经默认为空值 + 唯一索引了。
- 主键可以被其他表引用为外键,而唯一索引不能。
- 一个表最多只能创建一个主键,但可以创建多个唯一索引。
- 主键更适合那些不容易更改的唯一标识,如自动递增列、身份证号等。
- 在 RBO 模式下,主键的执行计划优先级要高于唯一索引。 两者可以提高查询的速度。
7.4 查询索引命令
- show index from 表名
- show keys from 表名
7.5 使用索引的代价
对DML(update、delete、insert)语句的效率,增删改会对索引影响,因为索引要重新整理。
7.6 注意事项
(1)存储引擎对索引的支持
(2)什么时候加索引
- 查询作为查询条件字段应该创建索引
- 唯一性太差的字段不适合单独创建索引,即使频繁
Select * from emp where sex=’男’
- 频繁更新字段,也不要定义索引。
- 不会出现在where语句的字段不要创建索引
(3)索引失效
- 模糊查询在like前面有百分号开头会失效。
- 如果条件中有or,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须建立索引, 我们建议大家尽量避免使用or 关键字
8 MySql优化
8.1 分表分库
(1)垂直拆分(拆分列)
垂直拆分就是要把表按模块划分到不同数据库表中(当然原则还是不破坏第三范式)。例如分布式情况下,为将一个项目进行拆分成多个子模块,每个子模块有单独数据库(解耦数据)。
(2)水平拆分(拆分行)
水平切分就是要把一个表按照某种规则把数据划分到不同表或数据库里。例如时间规则、地点、日志等,还有哈希算法。
(3)id主键处理方式
- UUID 适用于生成文件名,不适合作为主键,因为太长了。
- 不同步自增id,如主奇从偶
- redis生成id,但是让系统更复杂
8.2 读写分离
(1)主从复制
- 原理,主数据库将二进制日志文件(bin-log)传给从数据库。
- 触发时刻:从数据库监控主数据库二进制文件的变化,发生变化则通过IO线程进行二进制文件的复制和传输。
- 意义
1 数据丢失和备份
2 读写分离
3 负载均衡,高可用
(2)读写分离
- 定义:主数据库负责助理事务,从数据库负责读操作
- 意义
1 分摊服务器压力,提高机器的系统处理效率
2 增加冗余,提高系统可用性,可以在主数据库宕机式进行数据恢复
8.3 系统扩展
(1)垂直扩展(scale-up),在单机器上加存储、加内存、加CPU
(2)水平扩展(scale-out), 加机器数量,做集群
8.4 MyCat 中间件
(1)作用:分发请求,保证安全、读写分离、高可用、负载均衡
(2)原理:对数据进行分片处理,所有的分片数据库集群构成完整的数据库存储
· 阿里的rds系统
即开即用的关系型数据库服务,提供了强大丰富的功能,保证高可用性、安全性、高性能。
8.5 书写高质量SQL的30条建议
书写高质量SQL的30条建议
8.6 Order by 底层原理和SQL优化
order by 底层原理和优化查询案例
8.7 MySQL分页查询优化
分页查询的性能优化方案
sql进行Order by排序再进行分页limit取值会出现重复显示问题
mysql分页出现重复数据-order by
9 其他知识点
9.1 存储过程和函数
(1)就是一组SQL语句集,功能强大,可以实现一些比较复杂的逻辑功能,类似于JAVA语言中的方法。
(2)存储过程特性:
- 有输入输出参数,可以声明变量,有if/else, case,while等控制语句,通过编写存储过程,可以实现复杂的逻辑功能;
- 函数的普遍特性:模块化,封装,代码复用;
- 速度快,只有首次执行需经过编译和优化步骤,后续被调用可以直接执行。
(3)demo
· 创建一个存储过程
create procedure user_porced ()
begin
select name from users;
end;
· 调用存储过程
call porcedureName ();
· 传参存储过程
create PROCEDURE user_porcedPa(
in a int(10)
)
BEGIN
select * from users where age>a;
END;
> call user_porcedPa(10);
9.2 数据库备份
(1)手动方式
·cmd控制台:
在环境变量中配置mysql环境变量
mysqldump –u -账号–密码数据库[表名1 表名2..] > 文件路径
案例: mysqldump-u -root root test > d:\temp.sql
比如: 把temp数据库备份到 d:\temp.bak mysqldump -u root -proot test > f:\temp.bak
· 如果你希望备份是,数据库的某几张表
mysqldump -u root -proot test dept > f:\temp.dept.sql
· 如何使用备份文件恢复我们的数据.
mysql控制台
source d:\temp.dept.bak
(2)自动方式
把备份数据库的指令,写入到bat文件, 然后通过任务管理器去定时调用 bat文件.
mytask.bat 内容是:
@echo off
F:\path\mysqlanzhuang\bin\mysqldump -u root -proot test dept > f:\temp.dept.sql
创建执行计划任务执行脚本。
9.3 数据库范式
(1)作用:为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。
(2)三大范式
第一范式:1NF是对属性的原子性约束,要求属性(列)具有原子性,不可再分解;(只要是关系型数据库都满足1NF)
第二范式:2NF是对记录的惟一性约束,表中的记录是唯一的, 就满足2NF, 通常我们设计一个主键来实现,主键不能包含业务逻辑。
第三范式:3NF是对字段冗余性的约束,它要求字段没有冗余。 没有冗余的数据库设计可以做到。
还有 BCNF。
数据库的第一范式,第二范式,第三范式,BCNF范式理解sofency'Blog-CSDN博客数据库第三范式
9.4 慢查询
(1)使用show status使用show status查看MySQL服务器状态信息,包括了慢查询的次数
(2)慢查询定义:MySQL默认10秒内没有响应SQL结果,则为慢查询。可以去修改MySQL慢查询默认时间。
- 查询慢查询时间
show variables like 'long_query_time';
-- 修改慢查询时间
set long_query_time=1;
但是重启mysql之后,long_query_time依然是my.ini中的值
(3)在默认情况下,我们的mysql不会记录慢查询,需要在启动mysql时候,指定记录慢查询才可以,将慢查询定位到日志中。
9.5 SQL语句执行慢的原因
9.5.1 偶尔很慢
(1) 系统在刷新“脏页”中
当我们要往数据库插入一条数据、或者要更新一条数据的时候,我们知道数据库会在内存中把对应字段的数据更新了,但是更新之后,这些更新的字段并不会马上同步持久化到磁盘中去,而是把这些更新的记录写入到 redo log 日记中去,等到空闲的时候,在通过 redo log 里的日记把最新的数据同步到磁盘中去。当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。
· redolog写满了:redo log 里的容量是有限的,如果数据库一直很忙,更新又很频繁,这个时候 redo log 很快就会被写满了,这个时候就没办法等到空闲的时候再把数据同步到磁盘的,只能暂停其他操作,全身心来把数据同步到磁盘中去的,而这个时候,就会导致我们平时正常的SQL语句突然执行的很慢,所以说,数据库在在同步数据到磁盘的时候,就有可能导致我们的SQL语句执行的很慢了。
** · 内存不够用了:**如果一次查询较多的数据,恰好碰到所查数据页不在内存中时,需要申请内存,而此时恰好内存不足的时候就需要淘汰一部分内存数据页,如果是干净页,就直接释放,如果恰好是脏页就需要刷脏页。
(2)未获取到锁
要执行的这条语句,刚好这条语句涉及到的表,别人在用,并且加锁了,我们拿不到锁,只能慢慢等待别人释放锁了。或者,表没有加锁,但要使用到的某个一行被加锁了。
9.5.2 一直很慢
(1) 没有用上索引:例如该字段没有索引;由于对字段进行运算、函数操作导致无法用索引。
(2) 数据库选错了索引。
9.6 一条SQL语句的执行过程
10 常见问题总结
10.1 MySQL的字符串类型
在SQL中,将字符串类型分为了六类:char,varchar,text,blob,enum和set。
10.2 MySQL常用SQL语句大全
MySQL常用SQL语句大全_Sunshine-CSDN博客
10.3 MySQL数据库建库时SQL语句中数据库名、表名用引号的问题
解释:
在创建MySQL数据库和表时,数据库名、表名和字段名外面的符号 ` 不是单引号,而是英文输入法的反单引号,同键盘~同一位置。
为了避免你的表名和字段名 和数据库SQL中的关键字冲突。但也可以不加。
此外,需要注意,有部分程序员喜欢从网页上拷贝别人博客中的SQL脚本,在拷贝-粘贴的过程中容易将反单引号不经意间变为单引号,从而造成导入SQL脚本错误,请大家在开发时特别小心!!!
10.4 mysql表操作之建表时的列参数
https://baijiahao.baidu.com/s?id=1654339922439146488&wfr=spider&for=pc
10.5 MySQL数据库的高可用
MySQL数据库的高可用方案总结