MySQL数据库(预备知识)
MySQL数据库(预备知识)
一、MySQL
1、MySQL数据怎么存储数据、怎么优化数据索引、怎么实现事务的ACID、实际使用涉及哪些数据结构和算法、MySQL和Redis的区别是什么
2、数据库管理系统(DBMS-Database Management System)可以创建、查询、更新和删除数据。一个数据库可以使用多个数据引擎以满足各种性能和实际需求。
3、关系型数据库:建立在关系模型(一对一、一对多、多对多等)基础上的数据库,借助于集合代数等数学概念和方法来处理数据库中的数据库
4、非关系型模型比如有:列模型:Hbase; 键值对模型:Redis、MemcacheDB;文档类模型:mongoDB
5、关系型数据库通过外键关联来建立表与表之间的关系;非关系型数据库通常指数据以对象的形式存储在数据库中,而对象之间的关系通过每个对象自身的属性来决定
6、关系模型包括:数据结构(数据存储的问题,二维表)、操作指令集合(SQL语句)、完整性约束(表内数据约束、表与表之间的约束)
7、数据类型:整型、浮点型、十进制、字符、日期时间
8、数据库应用的开发使用的4个类:connection(连接)、statement(发送数据库操作指令)、resultset(传输在线数据)、dataset(传输离线数据)
9、MySQL服务器架构:图一、总的框架;图二、详细的框架
- 连接层:连接池:连接处理+授权验证+安全
- 服务层:Mangement Service(备份、安全、复制、集群)+SQL interface(存储过程、视图、触发器)+Parser解析(查询事务、对象权限)+Optimizer优化器+Cache Buffers
- 引擎层:负责 MYSQL 中数据的存储和提取,服务层通过API与存储引擎进行通信
二、关系型数据库管理系统
1、关系型数据库管理系统(RDBMS-Relational Database Management System):
- 数据以表格的形式出现
- 每行为各种记录名称 row
- 每列为记录名称所对应的数据域
- 许多的行和列组成一张表单
- 若干的表单(table)组成 database
2、MySQL数据库数据存放在硬盘当中,每次访问数据库时,都存在 I/O 操作。如果访问数据库次数频繁,反复连接数据库导致运行效率过慢
3、Redis的使用场景:排行榜、计数器、消息队列推送、好友关注、粉丝等访问数据频繁的场景。
三、MySQL的数据库引擎
1、InnoDB 引擎创建一个表,在硬盘上会生成.frm+.idb结尾的两个文件。索引和数据在以.idb结尾的文件中。InnoDB存储引擎在存储数据的时候,默认按照 b+ 树形结构存储数据。
2、MyISAM 引擎创建一个表,在硬盘上生成以.frm+.MYD+.MYI结尾的三个文件。frm结尾的是表结构(存什么字段什么类型),MYD结尾的是数据文件,MYI结尾的就是索引文件,所以索引也是存在硬盘上的
3、MEMORY 引擎,将表中的数据存储到内存中,未查询和引用其他表数据提供快速访问
注:
- 如果要提供提交、回滚、崩溃恢复能力的事务安全(ACID兼容)能力,并要求实现并发控制,InnoDB是一个好的选择
- 如果数据表主要用来插入和查询记录,则 MyISAM 引擎能提供较高的处理效率
- 如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,可以选择将数据保存在内存中的 Memory 引擎,MySQL中使用该引擎作为临时表,存放查询的中间结果
- 如果只有INSERT和SELECT操作,可以选择Archive,Archive支持高并发的插入操作,但是本身不是事务安全的。Archive非常适合存储归档数据,如记录日志信息可以使用 Archive
四、MySQL查询
1、MySQL查询方式
1、键和索引,MySQL中的key:primary key、unique key、index key。索引是一种存储引擎用于快速找到记录的一种数据结构。MySQL主要有两种索引数据结构:Hash 索引、B+Tree 索引。
2、数据库查询:等值查询、范围查询(>、<、between、in)、模糊查询(like)、并集查询(or)、
3、多列联合索引(最左前缀匹配原则)、聚集索引、非聚集索引、覆盖索引、
4、where子句
2、优化查询
1、查询优化器,一条SQL语句的查询,可以有不同的执行方案,至于选择哪种方案,需要通过优化器来选择
操作:
- 根据索引条件,找出所有可能使用的索引
- 计算全表扫描的代价
- 计算不同索引执行方案的代价
- 对比各种执行方案的代价,找出成本最低的那个方案
2、b+树索引:一次I/O操作读取的数据是一页;b+树叶子节点表示一个磁盘块也就是一页,存储数据项,b+树非叶子节点只存储指引搜索方向的数据项,不存储真实的数据
操作:
- 高度 h=㏒ (m+1)N(m=页面大小/数据项的大小、N为数据表的数据),所以索引字段要尽量的小(比如int占 4 字节,要比 bigint 8 字节少一半)
- 索引的最左匹配特性,(name,age,sex)的时候,b+树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据
- B+树索引可以分为聚集索引(clustered index)和辅助索引(secondary index)
五、MySQL 线上数据的事务隔离级别
1、SQL标准中定义了四种隔离级别:READ UNCOMMITTED(未提交读)、READ COMMITED(提交读)、REPEATABLE READ(可重复读)、SERIALIZABLE(可串行化)
2、隔离性的每一种级别多规定了:一个事务中所作的修改,哪些在事务内和事务间是可见;哪些是不可见!
- READ UNCOMMITTED(未提交读):事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据即脏读
- READ COMMITED(提交读)(大多数数据库系统的默认隔离级别,不包括 MySQL):一个事务开始时,只对已提交的事务所做的修改可见,即事务所作的修改直到提交之前所做的任何修改都是不可见的。NOREPEATABLE READ(不可重复读),两次执行同样的查询,可能得到不一样的结果(InnoDB 利用 consistent read view (一致读视图)方式支持的)
- REPEATABLE READ(可重复读)(MySQL默认级别):保证同一事务中多次读取同样的记录的结果是一致的! REPEATABLE READ(可重复读)无法解决 幻读(Phantom Read) 问题,幻读 指的是当摸个事务在读取某个范围内的记录时,会产生 幻行(Phantom Row)。InnoDB 和 XtraDB 通过多版本并发控制机制(MVVC) 解决幻读(Phantom Read) 问题((InnoDB 利用 consistent read view (一致读视图)方式支持的))
- SERIALIZABLE(可串行化):强制事务串行执行,避免了幻读(Phantom Read) 问题。SERIALIZABLE(可串行化)会在读取的每一行数据上都加锁,所以可能导致大量 超时和锁争用 的问题。使用场景:非常需要确保数据的一致性而且接受没有任何并发的情况下,使用SERIALIZABLE(可串行化)隔离级别
- 注:consistent read view:就是在某一时刻给事务系统 trx_sys 打 snapshot (快照),把当时的 trx_sys 状态(包括活跃读写事务数组)记下来,之后的所有读操作根据其事务ID(即trx_id)与snapshot中 trx_sys 的状态做比较,以此判断 read view(trx_sys 状态) 对事务(trx_id)的可见性
- 注:REPEATABLE READ隔离级别(除了GAP锁之外)和READ COMMITTED隔离级别的差别是创建snapshot时机不同:REPEATABLE READ隔离级别:创建snapshot时机是在事务开始时刻,确切的说是第一个读操作创建 read view 的时候;READ COMMITTED隔离级别:创建snapshot时机是在语句开始时刻创建 read view 的时候
- 注:REPEATABLE READ隔离级别下面一个事务的 SELECT 操作只会获取一个read view,但是 READ COMMITTED隔离级别下一个事务是可以获取多个read view
3、较低级别的隔离可以执行更高的并发,系统的开销也更低
4、每种储存引擎实现的隔离级别也不尽相同,不同的数据库产品的隔离级别的规定可能与预期不一致!
六、MySQL锁(LOCK)
1、锁的方案在实际应用环境虽然工作良好,但是并不支持并发处理,在同一时刻,只有一个线程可以使用加锁的资源!
2、锁分为共享锁和排他锁,共享锁又称为读锁,排他锁又称为写锁。写锁会阻塞其他的写锁和读锁,但是读锁之间不互相阻塞!写锁比读锁具有更高的优先级,写锁请求可能会插入到读锁对鞋的前面!
3、MySQL服务层和存储引擎都支持加锁!如果使用知识事务型引擎还显式在服务层对资源加锁,情况会变的非常复杂,在某些MySQL版本中甚至会出现一些无法预料的结果。LOCK TABLES 显式的加锁,只能在 autocommit 设置为 OFF 时,才能使用,其他都不能使用显式地加锁!
4、MySQL 锁的粒度分为:全局锁、表锁、行锁(表级锁、行级锁、页级锁)
- 全局锁
- 表锁(table lock)
表锁是 MySQL 中最基本的锁策略,并且开销最小的策略。表锁锁定整张表。一个用户在对表进行写操作(插入、删除、更新等)前,需要先获得写锁,这会阻塞其他用户对该表的所有读写操作。
- 行级锁(row lock)
行级锁最大程度支持并发处理,但是也带来最大的锁开销。InnoDB 和 XtraDB 中实现了行级锁,行级锁只在存储引擎层实现,而MySQL服务器层没有实现。服务器层完全不了解存储引擎中的锁实现。
5、MySQL 悲观锁(行锁,表锁等,读锁,写锁等)、乐观锁
- 悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)
- 乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量
- 注:乐观锁是一种思想,乐观锁不会锁住任何东西,即不依赖数据库的事务机制,乐观锁完全是应用系统层面的东西。所以它不是一种锁机制.如果使用乐观锁,那么数据库就必须加版本字段,否则就只能比较所有字段(浮点类型不能比较)
6、InnoDB 引擎采用两阶段锁定协议(2PL)
- 事务执行中,随时可以执行锁定,锁只有在执行 commit 或者 rollback 的时候才会释放,而且所有的锁都是同一时刻被释放。(隐式加锁)
- InnoDB 会根据隔离级别在需要时,自动加锁
7、MySQL 死锁
- 1、死锁:两个或多个事务在同一资源上占用,并请求锁定对方占用的资源,从而导致恶性循环的现象,当多个事务以不同的顺序锁定资源或同时锁定同一资源时,就有可能产生死锁!因为产生死锁的事务等待对方释放资源的锁的同时却有持有对方需要的锁,这就会陷入死循环,除非有外部因素介入才能解除死锁!
- 2、死锁产生的原因:资源上锁的行为和顺序是和具体存储引擎相关
- 资源冲突
- 储存引擎的实现方式导致
- 3、解决方案:
- 死锁检测
- 死锁超时机制
- 4、InnoDB 引擎解决死锁:将持有最少行级排他锁的事务进行回滚(相对比较简单的死锁混滚算法)