目录
数据库的三范式
MySQL数据库引擎
InnoDB与MyISAM的区别
数据库的事务
索引
SQL优化手段
drop、delete与truncate
视图
内联接、左外联接、右外联接
并发事务带来的问题
大表优化
1. 限定数据的范围
2. 读/写分离
3. 垂直分区
4. 水平分区
在 MySQL 中一条查询 SQL 是如何执行
索引优缺点
varchar 与 char 的区别
varchar(30) 中的 30 代表的涵义
int(11) 中的 11 的涵义
MySQL 索引类型
什么时候不要使用索引
MVCC
MySQL 数据库的锁
锁升级
避免死锁的出现
CHAR 和 VARCHAR 的区别
主键和候选键的区别
主键与索引的区别
MySQL 如何做到高可用方案
数据库的三范式
数据库三大范式包含:
1、第一范式(1NF);
2、第二范式(2NF);
3、第三范式(3NF)。
- 第一范式(1NF)的要求是属性不可分割
- 第二范式(2NF)的要求是满足第一范式,且不存在部分依赖
- 第三范式(3NF)的要求是满足第二范式,且不存在传递依赖
MySQL数据库引擎
- mysql常用引擎包括:MYISAM(读音)、Innodb、Memory、MERGE
- MYISAM:全表锁,拥有较高的执行速度,不支持事务,不支持外键,并发性能差,占用空间相对较小,对事务完整性没有要求,以select、insert为主的应用基本上可以使用这引擎
- Innodb:行级锁,提供了具有提交、回滚和崩溃回复能力的事务安全,支持自动增长列,支持外键约束,并发能力强,占用空间是MYISAM的2.5倍,处理效率相对会差一些
- Memory:全表锁,存储在内容中,速度快,但会占用和数据量成正比的内存空间且数据在 mysql重启时会丢失,默认使用HASH索引,检索效率非常高,但不适用于精确查找,主要用于那些内容变化不频繁的代码表
- MERGE:是一组MYISAM表的组合
InnoDB与MyISAM的区别
- InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;
- InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;
- InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
- InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;
- Innodb不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高;
数据库的事务
什么是事务?: 多条sql语句,要么全部成功,要么全部失败。
事务的特性:
数据库事务特性:原子性(Atomic)、一致性(Consistency)、隔离性(Isolation)、持久性 (Durabiliy)。简称ACID。
- 原子性:组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有操作都成功,整个事务才会提交。任何一个操作失败,已经执行的任何操作都必须撤销,让数据库返回初始状态。
- 一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的。即数据不会被破坏。如A转账100元给B,不管操作是否成功,A和B的账户总额是不变的。
- 隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,它们的操作不会对彼此产生干扰
- 持久性:一旦事务提交成功,事务中的所有操作都必须持久化到数据库中。
索引
- 官方介绍索引是帮助MySQL高效获取数据的数据结构。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
- 一般来说索引本身也很大,不可能全部存储在内存中,因此索引往往是存储在磁盘上的文件中的(可能存储在单独的索引文件中,也可能和数据一起存储在数据文件中)。
- 我们通常所说的索引,包括聚集索引、覆盖索引、组合索引、前缀索引、唯一索引等,没有特别说明,默认都是使用B+树结构组织(多路搜索树,并不一定是二叉的)的索引。
SQL优化手段
- 查询语句中不要使用select *
- 尽量减少子查询,使用关联查询(left join,right join,inner join)替代
- 减少使用IN或者NOT IN ,使用exists,not exists或者关联查询语句替代
- or 的查询尽量用 union或者union all 代替(在确认没有重复数据或者不用剔除重复数据时,union all会更好)
- 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
- 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from t where num=0
drop、delete与truncate
SQL中的drop、delete、truncate都表示删除,但是三者有一些差别
delete和truncate只删除表的数据不删除表的结构 速度,一般来说: drop> truncate >delete
delete 语句是dml,这个操作会放到rollback segement中,事务提交之后才生效; 如果有相应的trigger(触发器),执行的时候将被触发. truncate,drop是ddl, 操作立即生效,原数据不放到rollback segment中,不能回滚. 操作不触发trigger.
视图
视图是一种虚拟的表,具有和物理表相同的功能。可以对视图进行增,改,查,操作,视图通常是有一个表或者多个表的行或列的子集。对视图的修改不影响基本表。它使得我们获取数据更容易,相比多表查询。
内联接、左外联接、右外联接
- 内联接(Inner Join):匹配2张表中相关联的记录。
- 左外联接(Left Outer Join):除了匹配2张表中相关联的记录外,还会匹配左表中剩余的记录,右表中未匹配到的字段用NULL表示。
- 右外联接(Right Outer Join):除了匹配2张表中相关联的记录外,还会匹配右表中剩余的记录,左表中未匹配到的字段用NULL表示。在判定左表和右表时,要根据表名出现在Outer Join 的左右位置关系。
并发事务带来的问题
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。
脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
大表优化
1. 限定数据的范围
务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内;
2. 读/写分离
经典的数据库拆分方案,主库负责写,从库负责读;
3. 垂直分区
根据数据库里面数据表的相关性进行拆分。 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。
简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。
4. 水平分区
保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。
在 MySQL 中一条查询 SQL 是如何执行
1. 取得链接,使用 MySQL 中的连接器。
2. 查询缓存,key 为 SQL 语句,value 为查询结果,如果查到就直接返回。不建议使用次缓存,在MySQL 8.0 版本已经将查询缓存删除,也就是说 MySQL 8.0 版本后不存在此功能。
3. 分析器,分为词法分析和语法分析。此阶段只是做一些 SQL 解析,语法校验。所以一般语法错误在此阶段。
4. 优化器,是在表里有多个索引的时候,决定使用哪个索引;或者一个语句中存在多表关联的时候(join),决定各个表的连接顺序。
5. 执行器,通过分析器让 SQL 知道你要干啥,通过优化器知道该怎么做,于是开始执行语句。执行语句的时候还要判断是否具备此权限,没有权限就直接返回提示没有权限的错误;有权限则打开表,根据表的引擎定义,去使用这个引擎提供的接口,获取这个表的第一行,判断 id 是都等于 1。如果是,直接返回;如果不是继续调用引擎接口去下一行,重复相同的判断,直到取到这个表的最后一行,最后返回。
索引优缺点
优点
- 提高数据检索速度,降低数据库IO成本。
- 降低数据排序成本,降低CPU消耗,
缺点
- 占用存储空间
- 降低表更新的速度,表数据发生变化,对应的索引也需要一起变更
varchar 与 char 的区别
char 是一种固定长度的类型,varchar 则是一种可变长度的类型,对效率要求高用 char,对空间使用要求高用 varchar
varchar(30) 中的 30 代表的涵义
varchar(30) 中 30 的涵义最多存放 30 个字符。varchar(30) 和 (130) 存储 hello 所占空间一样,但后者在排序时会消耗更多内存,因为 ORDER BY col 采用 fixed_length 计算 col 长度(memory 引擎也一样)。
int(11) 中的 11 的涵义
int(11) 中的 11,不影响字段存储的范围,只影响展示效果
MySQL 索引类型
主键索引
索引列中的值必须是唯一的,不允许有空值。
普通索引
MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值。
唯一索引
索引列中的值必须是唯一的,但是允许为空值。
全文索引
只能在文本类型CHAR,VARCHAR,TEXT类型字段上创建全文索引。字段长度比较大时,如果创建普通索引,在进行like模糊查询时效率比较低,这时可以创建全文索引。MyISAM和InnoDB中都可以使用全文索引。
空间索引
MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型。MySQL在空间索引这方面遵循OpenGIS几何数据模型规则。
前缀索引
在文本类型如CHAR,VARCHAR,TEXT类列上创建索引时,可以指定索引列的长度,但是数值类型不能指定。
其他(按照索引列数量分类)
1. 单列索引
2. 组合索引
组合索引的使用,需要遵循最左前缀匹配原则(最左匹配原则)。一般情况下在条件允许的情况下使用组合索引替代多个单列索引使用。
什么时候不要使用索引
1. 经常增删改的列不要建立索引;
2. 有大量重复的列不建立索引;
3. 表记录太少不要建立索引。
MVCC
多版本并发控制(MVCC=Multi-Version Concurrency Control),是一种用来解决读 - 写冲突的无锁并发控制。也就是为事务分配单向增长的时间戳,为每个修改保存一个版本。版本与事务时间戳关联,读操作只读该事务开始前的数据库的快照(复制了一份数据)。这样在读操作不用阻塞写操作,写操作不用阻塞读操作的同时,避免了脏读和不可重复读。
MySQL 数据库的锁
MySQL 中有共享锁和排它锁,也就是读锁和写锁。
1. 共享锁:不堵塞,多个用户可以同一时刻读取同一个资源,相互之间没有影响。
2. 排它锁:一个写操作阻塞其他的读锁和写锁,这样可以只允许一个用户进行写入,防止其他用户读取正在写入的资源。
3. 表锁:系统开销最小,会锁定整张表,MyISAM 使用表锁。
4. 行锁:容易出现死锁,发生冲突概率低,并发高,InnoDB 支持行锁(必须有索引才能实现,否则会自动锁全表,那么就不是行锁了)。
锁升级
MySQL 行锁只能加在索引上,如果操作不走索引,就会升级为表锁。因为 InnoDB 的行锁是加在索引上的,如果不走索引,自然就没法使用行锁了,原因是 InnoDB 是将 primary key index 和相关的行数据共同放在 B+ 树的叶节点。InnoDB 一定会有一个 primary key,secondary index 查找的时候,也是通过找到对应的 primary,再找对应的数据行。
当非唯一索引上记录数超过一定数量时,行锁也会升级为表锁。测试发现当非唯一索引相同的内容不少于整个表记录的二分之一时会升级为表锁。因为当非唯一索引相同的内容达到整个记录的二分之一时,索引需要的性能比全文检索还要大,查询语句优化时会选择不走索引,造成索引失效,行锁自然就会升级为表锁。
避免死锁的出现
1. 设置获取锁的超时时间,至少能保证最差情况下,可以退出程序,不至于一直等待导致死锁
2. 设置按照同一顺序访问资源,类似于串行执行
3. 避免事务中的用户交叉
4. 保持事务简短并在一个批处理中
5. 使用低隔离级别
6. 使用绑定链接
CHAR 和 VARCHAR 的区别
- CHAR 和VARCHAR 类型在存储和检索方面有所不同
- CHAR 列长度固定为创建表时声明的长度,长度值范围是1 到255当 CHAR 值被存储时,它们被用空格填充到特定长度,检索CHAR 值时需删除尾随空格。
主键和候选键的区别
表格的每一行都由主键唯一标识,一个表只有一个主键。主键也是候选键。按照惯例,候选键可以被指定为主键,并且可以用于任何外键引用。
主键与索引的区别
- 主键一定会创建一个唯一索引,但是有唯一索引的列不一定是主键;
- 主键不允许为空值,唯一索引列允许空值;
- 一个表只能有一个主键,但是可以有多个唯一索引;
- 主键可以被其他表引用为外键,唯一索引列不可以;
- 主键是一种约束,而唯一索引是一种索引,是表的冗余数据结构,两者有本质的区别
MySQL 如何做到高可用方案
MySQL 高可用,意味着不能一台 MySQL 出了问题,就不能访问了。
- MySQL 高可用:分库分表,通过 MyCat 连接多个 MySQL
- MyCat 也得高可用:Haproxy,连接多个 MyCat
- Haproxy 也得高可用:通过 keepalived 辅助 Haproxy
近日总结:昨天的昨天跑步,跑的有点猛了,腿疼......呜呜呜腿疼.......呜呜呜......