1、MySQL三范式
第一范式:列不可再分
第二范式:主键约束
第三范式:外键约束,表的非主属性不能依赖与其它表的非主属性
存储引擎
查看MySQL的存储引擎
mysql> show engines;
MySQL常用存储引擎:MYISAM、InnoDB
MYISAM:全表锁,不支持事务,不支持外键、并发性能差,支持全文索引,占用空间相对较小,查询性能更好。
InnoDB:行锁,支持事务、支持外键,并且提供了提交、回滚、崩溃恢复的事务安全,并发能力强,占用空间更大,默认事务隔离级别为可重复读。
MYISAM与InnoDB区别:
1、InnoDB支持事务,MYISAM不支持
2、InnoDB是聚簇索引,数据文件是和索引绑定在一起的,必须有主键,通过主键索引效率更高,辅助索引需要进行两次查询,先查询到主键,然后通过主键查询到数据,因此主键不应该过大,因为主键太大会造成其它索引也会很大。MYISAM是非聚簇索引。
3、InnoDB不保存表的数据行数,执行select count() from table_name会全表扫描,而MYISAM通过一个变量保存了表的具体行数,执行select count() from table_name速度很快。
如何选择
以读写插入为主的程序,使用MYISAM效率更高。对于更新频率高并且保持并发性、数据完整性支持事务和外键的则使用InnoDB。
行锁
MySQL中行锁包括:间隙锁、排他锁、共享锁。
数据库事务
什么是事务?
事务是执行多条sql语句,要么全部执行成功,要么全部失败。
事务的特性
原子性:组成事务的多个数据库操作要么全部执行成功要么全部失败,只有所有操作全部执行成功事务才会提交,任何一个操作执行失败,已经执行的操作也必须撤销,让数据库返回初始状态。
一致性:事务执行成功后,数据库所处的状态和业务规则是一致的,也就是数据不会被破坏。
隔离性:并发数据操作时,不同的事务是相互隔离的,彼此之间的执行互不影响。
持久性:一旦事务执行成功,事务所有的操作必须持久化到数据库中。
事务的实现
事务的实现是根据预写日志的方式来实现的,MySQL中的redo log和undo log是实现数据库事务的基础,redo log用来在断电或者数据库崩溃等情况发生时重新刷数据,将redo log中的数据刷新到数据库中,保证事务的持久性;undo log在事务操作失败时撤销对事务的操作,保证事务的原子性。
索引
索引是对数据库表中一个或多个列的值进行排序的结构,建立索引有助于快速查询。
可以将索引理解为加快查询数据库数据的方法,数据库中的索引类似于书的目录,在数据库中可以根据索引快速找到数据而不需要进行全表扫描。
索引类型:
主键索引:一个表只能有一个主键,也就只能有一个主键索引
唯一索引:数据列不允许重复,允许为null值,一个表允许有多个唯一索引
ALTER TABLE table_name ADD UNIQUE (columns)
普通索引:普通索引中可以允许重复值,可以通过ALTER TABLE table_name ADD INDEX (columns)
全文索引:全文索引是对文本的内容进行分词然后搜索,实现方式为ALTER TABLE table_name ADD INDEX (columns1,columns2)
组合索引:组合索引用于多个列组成的索引,用于组合搜索,实现方式ALTER TABLE table_name ADD FULLTEXT (columns)
索引优缺点
缺点:
索引并非越多越好,创建索引也需要消耗资源,索引也会增加数据库资源,并且在插入和删除时需要维护索引。
优点:
索引加快数据库的检索速度
唯一索引可以确保每一行数据的唯一性
通过使用索引可以在查询的过程中使用优化隐藏器,提高系统性能
索引
索引的实现
在MySQL中索引是通过B+Tree来实现的,在B+Tree中非叶子节点只保存索引,所有的数据保存在叶子节点中,叶子节点中使用指针来指向下一个数据,所以适合范围查找,所有的数据都保存在叶子节点中,所以所有关键字查询的路径都是相同的,即每个数据查询效率相当。
索引优化
1、查询语句中不要使用select *
2、尽量减少子查询,使用关联查询替代
3、减少使用IN或者NOT IN,使用exist,not exist替代,这是因为IN和NOT IN会全表扫描
4、避免使用OR,可以使用union或者union all代替
5、避免在where后面使用sql函数,如!= 、<>,否则将放弃索引而进行全表扫描
6、避免在where后面对字段进行null判断
并发事务带来的问题
脏读:当一个事务正在访问数据并对数据做了修改,而这个修改还没有提交到数据库中,这是另一个事务也访问了这个数据,这时候前一个事务修改了数据还没提交但是数据已经被其它事务使用了,其它事务使用的数据就是脏数据。
不可重复读:一个事务多次读取同一个数据,另一个事务在第一个事务两次读取数据之间修改了数据,那么第一个事务第一次读取的数据和第二次读取的数据就会不一样,这种情况发生在一个事务多次读取数据,读取的数据不一致的情况。
幻读:幻读与不可重复读类似,它的情况是一个事务读取了一些数据,接着另一个事务插入了几条数据,第一个数据再执行查询操作时就会发现比原来多了一些原来不存在的数据。
不可重复读与幻读的区别,幻读的重点在于数据新增或者删除了一些,而不可重复读是数据被修改了。
事务隔离级别
读未提交:最低的隔离级别,允许读取到尚未提交的数据,可能会导致脏读、不可重复读、幻读
读已提交:允许读取并发事务已提交的数据,可以阻止脏读、但是幻读、不可重复读可能发生
可重复度:对同一字段的多次读取结果是一致的,可以阻止脏读和不可重复读,但幻读可能发生
可串行化:最高的隔离级别,所有的事务依次逐个执行,这样事务之间不会干扰,该级别可以防止脏读、不可重复度、幻读。
InnoDB虽然使用的是可重复读,但是InnoDB事务隔离级别下使用的是Next-key-Lock算法,这个算法可以避免幻读的产生。
在InnoDB中有三种行锁的算法:
1、Record Lock:单个行记录上的锁
2、Gap Lock:间隙锁,锁定一个范围但是不包括记录本身。GAP锁的目的是防止同一事务的两次当前读出现幻读的情况。
3、Next-key-Lock:锁定一个范围,并且记录行本身。对于行的查询,都是采用该方法,主要就是解决幻读的问题。
多版本并发控制
MVCC是多版本并发控制,是为了解决在MySQL中多个并发事务造成的脏读、不可重复读、幻读的问题。
MySQL中的事务隔离级别为四个,MVCC只在可重复读和读已提交两个级别中工作。
InnoDB的MVCC是通过在每行记录后面保存两个隐藏列来实现的,一列是行的创建时间,一列是行的过期时间,存储的是版本号而不是真实的事件,每个新的事务操作了该行,那么系统版本号就会递增,事务开始时刻的版本号作为事务版本号,用来和查询到的每行记录的版本号做比较。类似乐观锁中的版本控制。
