目录
1 表设计
1.1 存储引擎
1.2 存储引擎特点
1.2.1 InnoDB
1.2.2 MyISAM
1.2.3 Memory
2 表结构设计
2.1 范式设计,消除冗余
2.2 反范式设计,适当冗余
2.3.主键
2.4.选择数据类型
3 索引
3.1 什么是索引
3.2 索引的分类
3.3 索引的优缺点
3.4 索引失效
3.5 索引优化
4 触发器
4.1 概念
4.2 触发器类型
4.3 触发器优缺点
5 锁
5.1 行级锁
5.2 InnoDB 中的两个表锁
存储引擎:存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表的,而不是基于库的,所以存储引擎也被称为表类型
注意:索引是在引擎层完成的,不同的存储引擎 他的索引结构不同
查询当前数据库支持的存储引擎,MySQL5.5后默认的存储引擎INNODB 之前默认支持MyISAM
show engines;
在创建表时,指定存储引擎
create table 表名(
字段 数据类型 约束,
字段 数据类型 约束
) engine = 存储引擎名称;
介绍:InnoDB是一种兼顾高可靠和高性能的通用存储引擎,在MySQL5.5之后,InnoDB是默认的MySQL存储引擎
特点
DML操作遵循ACID原则,支持事务;
支持行锁,采用MVCC来支持高并发 ;
支持外键FROEIGN KEY约束,保证数据的完整性和正确性;
支持崩溃后的安全恢复;
不支持全文索引
MVCC :mvcc全称是multi version concurrent control(多版本并发控制)。mysql把每个=操作都定义成一个事务,每开启一个事务,系统的事务版本号自动递增。每行记录都有两个隐藏列:创建版本号和删除版本号
文件存储
XXX.ibd:xxx代表的是表名,innoDB引擎的额每张表都会对应这样一个表空间文件,存储该表的表结构(frm、sdi)、数据和索引。
sdi数据字典,mysql8.0以前存储在frm文件中,mysql8.0之后就存储在sdi中
参数:innodb_file_per_table
MyISAM是MySQL早期默认的存储引擎
特点
不支持事务,不支持外键
支持表锁,不支持行锁
访问速度快
在表有读取查询的同时,支持往表中插入新纪录
对于不会进行修改的表,支持压缩表,极大减少磁盘空间占用
介绍:Memory引擎的表结构存储数据在内存中,由于受到硬件问题、电源问题的影响,只能将这些表作为临时表或缓存使用。
特点
内存存放--访问速度快
支持hash索引
三者间的对比:
数据库范式是确保数据库结构合理,满足各种查询需要、避免数据库操作异常的数据库设计方式。满足范式要求的表,称为规范化表,范式产生于20世纪70年代初,一般表设计满足前三范式就可以。
通俗的三范式解释:
数据库设计的实用原则是:在数据冗余和处理速度之间找到合适的平衡点,满足范式的表一定是规范化的表,但不一定是最佳的设计。
很多情况下会为了提高数据库的运行效率,常常需要降低范式标 准:适当增加冗余,达到以空间换时间的目的。比如我们有一个表,产品名称,单价,库存量,总价值。这个表是不满足第三范式的,因为“总价值”可以由“单价”乘以“数量”得到,说明“金额”是冗余字段。但是,增加“总价值”这个冗余字段,可以提高查询统计的速度,这就是以空间换时间的作法。合理的冗余可以分散数据量大的表的并发压力,也可以加快特殊查询的速度,冗余字段可以有效减少数据库表的连接,提高效率。
主键:根据第二范式,需要有一个字段去标识这条记录,主键无疑是最好的标识,需要满足唯一性、非空性,但是很多表也不一定需要主键,但是对于数据量大,查询频繁的数据库表,一定要有主键,主键可以增加效率、防止重复等优点。
MySQL支持的数据类型非常多, 选择正确的数据类型对于获得高性能至关重要。
更小的通常更好 更小的数据类型通常更快, 因为它们占用更少的磁盘、 内存和CPU缓存, 并且处理时需要的CPU周期也更少。
简单就好 简单数据类型的操作通常需要更少的CPU周期。 例如, 整型比字符操作代价更低, 因为字符集和校对规则(排序规则 )使字符比较比整型比较更复杂。
尽量避免NULL
如果查询中包含可为NULL 的列, 对MySQL来说更难优化, 因为可为NULL 的列使得索引、 索引统计和值比较都更复杂。
数据类型尽量用数字型,数字型的比较比字符型的快很多
在数据之外,数据库还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用指向数据,这样就可以在这些数据结构上实现高效查找,这些数据结构就是索引。
简单来说索引的出现就是为了提高数据的查询效率,就像书的目录一样。在书籍中,用户不必翻阅完整个书就能根据目录迅速地找到所需要的信息。在数据库中,索引也允许数据库程序迅速地找到表中的数据,而不必扫描整个数据库。
单值索引:一个索引只包含单个列,一个表中可以有多个单值索引
唯一索引:索引列的值必须唯一,可为空
复合索引:一个索引包括多个列
优点:
1.提高数据检索效率,降低磁盘IO成本
2.通过对数据的排序,降低排序成本
缺点:
1.索引虽提高了查询效率,但同时降低了更新、修改、删除的效率,因为MySQL不仅要保存数据,还要维护数据和索引的关系。
2.需要成本去维护索引。一个性能良好的索引需要不断的去尝试,以找到最优解。
1、like以通配符开头('%abc')会导致索引失效,违反最左前缀法则
最左前缀法则:如果索引了多列(联合索引)。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃某一列,索引将部分失效(后面的字段索引失效)
2、在索引列上做任何操作(计算、函数、类型转换),会导致索引失效而转向全表扫描
3、存储引擎不能使用索引中范围条件右边的列,举例:select id,name from student where id > 50 and name = '张三',会导致name索引失效
4、尽量使用覆盖索引,不要select *
5、MySQL在使用不等于(!=或<>)的时候无法使用索引会导致全表扫描,理由也很简单,B+Tree叶子节点用指针相连且是排好序的,这种数据结构只能解决有序的定值查询,像不等于这种无法利用索引查询。
6、IS NULL、IS NOT NULL无法使用索引,理由同上
7、字符串不加单引号索引失效
隐式转换-->函数操作
8、用or连接时会导致索引失效
前缀索引优化:使用某个字段中字符串的前几个字符建立索引
使用前缀索引是为了减小索引字段大小,可以增加一个索引页中存储的索引值,有效提高索引的查询速度。在一些大字符串的字段作为索引时,使用前缀索引可以帮助我们减小索引项的大小。
前缀索引的局限性:
1、order by 无法使用前缀索引;
2、无法把前缀索引用作覆盖索引;
覆盖索引优化:SQL 中 query 的所有字段,在索引 B+Tree 的叶子节点上都能找得到的那些索引,从二级索引中查询得到记录,而不需要通过聚簇索引查询获得,可以避免回表的操作。
使用覆盖索引的好处就是,不需要查询出包含整行记录的所有信息,也就减少了大量的 I/O 操作。
主键索引最好是自增的:InnoDB 创建主键索引默认为聚簇索引,数据被存放在了 B+Tree 的叶子节点上。也就是说,同一个叶子节点内的各个数据是按主键顺序存放的,因此,每当有一条新的数据插入时,数据库会根据主键将其插入到对应的叶子节点中。
如果我们使用自增主键,那么每次插入的新数据就会按顺序添加到当前索引节点的位置,不需要移动已有的数据,当页面写满后,就会自动开辟一个新页面。因为每次插入一条新记录,都是追加操作,不需要重新移动数据,因此这种插入数据的方法效率非常高。
如果我们使用非自增主键,由于每次插入主键的索引值都是随机的,因此每次插入新的数据时,就可能会插入到现有数据页中间的某个位置,这将不得不移动其它数据来满足新数据的插入,甚至需要从一个页面复制数据到另外一个页面,我们通常将这种情况称为页分裂。页分裂还有可能会造成大量的内存碎片,导致索引结构不紧凑,从而影响查询效率。
索引最好设置为NOT NULL
第一原因:索引列存在 NULL 就会导致优化器在做索引选择的时候更加复杂,更加难以优化,因为可为 NULL 的列会使索引、索引统计和值比较都更复杂,比如进行索引统计时,count 会省略值为NULL 的行。
第二个原因:NULL 值是一个没意义的值,但是它会占用物理空间,所以会带来的存储空间的问题,会导致更多的存储空间占用,因为 InnoDB 默认行存储格式COMPACT,会用 1 字节空间存储 NULL 值列表
防止索引失效
触发器(trigger)是个特殊的存储过程,它的执行不是由程序调用,也不是手工启动,而是由事件来触发,比如当对一个表进行操作( insert,delete, update)时就会激活它执行。
作用:
触发器经常用于加强数据的完整性约束和业务规则等;
可在写入数据前,强制检验或者转换数据(保证安全性);
触发器发生错误时,前面用户已经执行成功的操作会被撤销,类似事务的回滚。
触发器是与表有关的数据库对象,指在insert/update/delete之前或之后,触发并执行触发器定义的sql语句。使用别名OLD和NEW来引用触发器中发生变化的记录内容,现在的触发器只支持行级触发,不支持语句级触发
优点
安全性
触发器有回滚性,保证数据完整
保存用户的操作,存入日志
触发器可以对数据库中的相关表进行连环更新
缺点
过分依赖触发器,影响数据库的结构,增加数据库的维护成本
MySQL的InnoDB锁机制分为表级锁和行级锁
行级锁中有共享锁和排它锁。
共享锁又称为读锁,简称S锁,顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。
select * from t_user where id =10 lock in share mode;
排他锁又称为写锁(独占锁),简称X锁,顾名思义,排他锁就是不能与其他锁并存。
如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,
包括共享锁和排他锁。
select * from t_user where id =10 for update;
MySQL InnoDB引擎默认的修改数据语句,update,delete,insert都会自动给涉及到的数据加上排他锁,select语句默认不会加任何锁类型。
意向共享锁(IS):表示事务准备给数据行加入共享锁,也就是说一个数据行加共享锁前必须先取得该表的IS锁;
意向排他锁(IX):类似上面,表示事务准备给数据行加入排他锁,说明事务在一个数据行加排他锁前必须先取得该表的IX锁。
意向锁是 InnoDB 自动加的,不需要用户干预。
再强调一下,对于INSERT、UPDATE和DELETE,InnoDB 会自动给涉及的数据加排他锁;对于一般的SELECT语句,InnoDB 不会加任何锁,事务可以通过以下语句显式加共享锁或排他锁。
共享锁:SELECT … LOCK IN SHARE MODE;
排他锁:SELECT … FOR UPDATE;
两种锁的优劣
表锁的优势:开销小;加锁快;无死锁 表锁的劣势:锁粒度大,并发处理能力低
行锁的劣势:开销大;加锁慢;会出现死锁 行锁的优势:锁的粒度小,处理并发的能力