网站开发流程可规划为那三个阶段,竞价推广返点开户,做远程培训网站用什么系统,郑州哪里教做网站一、MySQL组成
MySQL数据库的连接池#xff1a;由一个线程来监听一个连接上请求以及读取请求数据#xff0c;解析出来一条我们发送过去的SQL语句SQL接口#xff1a;负责处理接收到的SQL语句查询解析器#xff1a;让MySQL能看懂SQL语句查询优化器#xff1a;选择最优的查询…一、MySQL组成
MySQL数据库的连接池由一个线程来监听一个连接上请求以及读取请求数据解析出来一条我们发送过去的SQL语句SQL接口负责处理接收到的SQL语句查询解析器让MySQL能看懂SQL语句查询优化器选择最优的查询路径执行器根据执行计划调用存储引擎的接口存储引擎接口真正执行SQL语句
二、InnoDB的数据更新过程
首先InnoDB存储引擎有一个重要内存结构为缓冲池假设我们执行如下sql:
update users set namexxx where id10那么底层将有如下几个步骤
看看“id10”这一行数据是否在缓冲池里如果不在的话直接从磁盘里加载到缓冲池里来对这行记录加独占锁假设“id10”这行数据的name原来是“zhangsan”现在我们要更新为“xxx”先把要更新的原来的值“zhangsan”和“id10”这些信息写入到undo日志文件中去更新buffer pool中的缓存数据现在已经把内存里的数据进行了修改但是磁盘上的数据还没修改这个时候就必须要把对内存所做的修改写入到一个redo日志提交事务的时候将redo日志写入磁盘中
三、MySQL自己的日志文件binlog
binlog叫做归档日志他里面记录的是“对users表中的id10的一行数据做了更新操作更新以后的值是什么”提交事务的时候同时会写入binlog到磁盘文件中去
四、MySQL核心结构
Buffer Pool Buffer Pool本质其实就是数据库的一个内存组件默认情况下是128MB还是有一点偏小了我们实际生产环境下完全可以对Buffer Pool进行调整。数据库启动时会在Buffer Pool中划分出来一个一个的缓存页一个缓存页的大小和磁盘上的一个数据页的大小是一一对应起来的都是16KB每个数据页中有很多行数据。 free链表 他是一个双向链表数据结构只要你一个缓存页是空闲的 那么他的描述数据块就会被放入这个free链表中当你需要把磁盘上的数据页读取到Buffer Pool中的缓存页里去的时候我们需要从free链表里获取一个描述数据块然后就可以获取对应的空闲缓存页接着我们就可以把磁盘上的数据页读取到对应的缓存页里去最后把那个描述数据块从free链表里去除就可以了。 数据页缓存哈希表 我们在执行增删改查的时候肯定是先看看这个数据页有没有被缓存用表空间号数据页号作为一个key然后缓存页的地址作为value。 flush链表 凡是被修改过的缓存页都会把他的描述数据块加入到flush链表中去flush的意思就是这些都是脏页后续都是要flush刷新到磁盘上去的。 五、事务
四大事务问题
脏写事务B更新好的值被事务A回滚为事务A原先的值。脏读事务B去查询了事务A修改过的数据但是此时事务A还没提交不可重复读事务A执行过程中事务B执行并提交导致事务A两次读到的值不一样幻读事务A一开始查出了10条数据事务B新增了2条数据并且提交了此时事务A再查发现查出了12条数据
四大隔离级别
read uncommitted读未提交不允许发生脏写的可能发生脏读不可重复读幻读。read committed读已提交不会发生脏写和脏读可能会发生不可重复读和幻读问题repeatable read可重复读不会发生脏写和脏读和不可重复读可能会幻读问题serializable串行化不会发生脏写和脏读和不可重复读和幻读
MySQL默认设置的事务隔离级别是可重复读而且MySQL的可重复读级别是可以避免幻读发生的原理就是下面的MVCC机制。
六、MVCC机制
Mysql事务通过MVCC机制得以实现我们每条数据其实都有两个隐藏字段一个是trx_id一个是roll_pointer这个trx_id就是最近一次更新这条数据的事务idroll_pointer就是指向你了你更新这个事务之前生成的undo log链。 执行一个事务的时候就给你生成一个ReadView(视图)ReadView包含以下信息
m_ids此时有哪些事务在MySQL里执行还没提交的min_trx_idm_ids里最小的值max_trx_idmysql下一个要生成的事务id就是最大事务idcreator_trx_id你这个事务的id
下面演示一下MVCC机制的执行步骤
一个是事务Aid45一个是事务Bid59事务B是要去更新这行数据的事务A是要去读取这行数据的值现在事务A直接开启一个ReadView这个ReadView里的m_ids就包含了事务A和事务B的两个id45和59然后min_trx_id就是45max_trx_id就是60creator_trx_id就是45是事务A自己。这个时候事务A第一次查询这行数据会走一个判断就是判断一下当前这行数据的txr_id是否小于ReadView中的min_trx_id此时发现txr_id32是小于ReadView里的min_trx_id就是45的说明你事务开启之前修改这行数据的事务早就提交了所以此时可以查到这行数据接着事务B开始动手了他把这行数据的值修改为了值B然后这行数据的txr_id设置为自己的id也就是59同时roll_pointer指向了修改之前生成的一个undo log接着这个事务B就提交了这个时候事务A再次查询此时查询的时候会发现一个问题那就是此时数据行里的txr_id59那么这个txr_id是大于ReadView里的min_txr_id(45)同时小于ReadView里的max_trx_id60的说明更新这条数据的事务很可能就跟自己差不多同时开启的于是会看一下这个txr_id59是否在ReadView的m_ids列表里果然在ReadView的m_ids列表里有45和59两个事务id直接证实了这个修改数据的事务是跟自己同一时段并发执行然后提交的所以对这行数据是不能查询的顺着这条数据的roll_pointer顺着undo log日志链条往下找就会找到最近的一条undo logtrx_id是32此时发现trx_id32是小于ReadView里的min_trx_id45的说明这个undo log版本必然是在事务A开启之前就执行且提交的那么读这条数据就可以了总结来说一个事务可以读到事务ID等于自身和比自己事务ID小的事务更新的值但是也不是所有的事务ID比自己小的事务更新的值都能读到还不能不在m_ids中
七、锁机制
当有一个事务加了独占锁之后此时其他事务再要更新这行数据只能生成独占锁在后面等待。当有人在更新数据的时候其他的事务可以读取这行数据吗默认情况下需要加锁吗不用因为有人在更新数据的时候然后你要去读取这行数据直接默认就是开启mvcc机制的。那么假设万一要是你在执行查询操作的时候就是想要加锁呢那也是ok的MySQL首先支持一种共享锁就是S锁这个共享锁的语法如下select * from table lock in share mode如果此时有别的事务在更新这行数据已经加了独占锁了此时你的共享锁能加吗当然不行了共享锁和独占锁是互斥的此时你这个查询就只能等着了。那么如果你先加了共享锁然后别人来更新要加独占锁行吗当然不行了共享锁和独占锁是互斥的此时你这个查询就只能等着了。那么如果你在加共享锁的时候别人也加共享锁呢此时是可以的你们俩都是可以加共享锁的共享锁和共享锁是不会互斥的。
八、索引
MySQL的索引是用B树来组成的索引分为两种
聚簇索引 如果一颗大的B树索引数据结构里叶子节点就是数据页自己本身那么此时我们就可以称这颗B树索引为聚簇索引这个聚簇索引默认是按照主键来组织的所以你在增删改数据的时候一方面会更新数据页另一方面其实会给你自动维护B树结构的聚簇索引。 二级索引 比如你基于name字段建立了一个索引那么此时你插入数据的时候就会重新搞一颗B树B树的叶子节点也是数据页但是这个数据页里仅仅放主键字段和name字段。针对select * from table where namexx’这样的语句你先根据name字段值在name字段的索引B树里找找到叶子节点也仅仅可以找到对应的主键值而找不到这行数据完整的所有字段。 索引使用原则
等值匹配规则 就是你where语句中的几个字段名称和联合索引的字段完全一样而且都是基于等号的等值匹配那百分百会用上我们的索引 最左侧列匹配 这个意思就是假设我们联合索引是KEY(class_name, student_name, subject_name)那么不一定必须要在where语句里根据三个字段来查其实只要根据最左侧的部分字段来查也是可以的。 最左前缀匹配原则 即如果你要用like语法来查比如select * from student_score where class_name like ‘1%’查找所有1打头的班级的分数那么也是可以用到索引的。 范围查找规则 你的where语句里如果有范围查询那只有对联合索引里最左侧的列进行范围查询才能用到索引 等值匹配范围匹配的规则 联合索引是KEY(class_name, student_name, subject_name)如果你要是用select * from student_score where class_name‘1班’ and student_name‘’ and subject_name‘’首先可以用class_name在索引里精准定位到一波数据接着这波数据里的student_name都是按照顺序排列的所以student_name‘也会基于索引来查找但是接下来的subject_name’是不能用索引的。为什么呢因为student_name在不相同的情况下subject_name是无序的所以不能走索引只能全表扫描。 执行计划的几个级别
const 直接就可以通过聚簇索引或者二级索引聚簇索引回源轻松查到你要的数据。这里有一个要点你的二级索引必须是unique key唯一索引才是属于const方式的 ref select * from table where namex的语句name是个普通二级索引不是唯一索引如果你用name IS NULL这种语法的话即使name是主键或者唯一索引还是只能走ref方式 range select * from table where agex and age x假设age就是一个普通索引此时就必然利用索引来进行范围筛选 index 只要遍历二级索引就可以拿到你想要的数据而不需要回源到聚簇索引的访问方式 all 全表扫描