(最高版本)mysql数据库

128 阅读15分钟

数据库结构模型

客户端,也就是如jdbc 服务端:服务管理(连接池,sql存储,sql解析,sql优化,sql缓存), 存储引擎(数据存储的结构),文件层(存储数据文件,日志),同时mysql的存储引擎时可插拔式的,

模型图:

-数据库的锁及事务

  • 数据库的锁划分 控制粒度:行锁,表锁,页面锁

按级别划分:共享锁(也就是读锁,被上锁的数据,只能被多个线程读取,而不能写操作),排它锁(写锁,只能被当前线程执行写的操作,而其他的线程不可以对被锁的数据进行写或者读的操作)

使用方式划分:乐观锁(CAS 实现,版本号实现),悲观锁(读锁和写锁)

按枷锁的方式:自动锁(增删改的时候上锁),显式锁(查询语句使用上锁语句 给表上锁读锁 lock tables tablename read 解锁 unlock tables 表独占写锁:Table tables tablename Write

myisam:表锁(不支持事务) myisan在查询的时候,会对这个表进行上锁,所以这个过程中,多表进行修改时,需要先等待查询完,再更新 myisam对数据进行读和写的时后,都会对表上锁

操作划分:ddl锁,dml锁

  • 事务 事务的四大特点: 1、原子性(操作要么成功,要么失败);触发了2

2、一致性(操作前后的数据状态是一致的);对数据的修改,有日志的记录,实现回退

3、隔离级别(事务将数据不受影响的程度);

4、持久性(保存到磁盘)。

事务的隔离级别4种:重要(事务的隔离级别,是通过延长操作的数据是否锁的时间(是否提交事务)和设置锁的粒度(行,表),锁的类型(读写锁))来实现的。

读未提交; 读已提交(oracle默认的隔离级别); 重复读(mysql 的inndb默认的级别); 串行读。

在并发的环境下,数据会出现以下的问题,可以通过调整事务的隔离级别去处理:

幻读:当事务在第二次查询数据的是否,发现查询的条件,多出了其他的数据(其他的事务插入)(通过设置事务隔离级别为 串行读)增加数据条数 (该事务增加了读锁表级读锁))

不可重复读:事务在读取某个数据的一段时间以后,数据再次读取,前后的数据不一致(因为在这个期间,有其他的事务对数据进行了修改并且已提交)。(隔离级别设为 重复读)(该事务增加了读锁行级读锁,)

脏读:当一个事务对数据进行了修改,但是没有被提交,这时,其他的事务读取到了这个事务没有被修改的数据。 隔离级别设为 读已提交(写锁在提交事务后释放?需要检验)

丢失更新:当多个事务选择同一行,最初事务修改的值(事务未提交),会被后面事务修改的值覆盖(增加事务,事务增加了写锁,)(写锁在提交事务后释放,事务隔离级别必有)

锁与事务隔离级别的关系:事务的隔离级别,是通过延长操作的数据是否锁的时间(是否提交事务)和设置锁的粒度(行,表),锁的类型(读写锁)来实现的。()

存储引擎及存储索引数据结构介绍

工作中,mysql主要使用的存储引擎有:inndb和myisam。

innodb:支持行级锁,事务和外键。适用于增删改频发的业务场景,因为支持事务,可靠性较强

inndb默认的事务隔离级别是 重复读(也就是在读数据的时候,会对读取的数据上行级读锁,和写锁)

  • 索引的数据结构:二叉树;B-tree;B+-tree;hash结构,bitmap

二叉树(每个树的节点,最多只有两个子节点,左父右依次增大

二叉树的缺点是,数据量大的时候,树结构太深,查询效率减低就会产生多次的io,也花费很多的时间

B-tree,使用的是平衡二叉树的结构,解决了二叉树的数深度问题

特点:数据都存储在 各个节点上, B+-tree 使用的是平衡二叉树,数据统一存储在节点上,相对于B-tree,可以一次加载更多的索引,减少io次数, 同时,innodb的B+-tree做了优化,在每个子节点间增加了指针,这可以用于范围查询的快速定位

hash结构:

对于特定条件的查询,有较高的效率,但是不能用于范围的查询

hash结构 索引类型: 主键索引(聚集索引),普通索引,复合索引(使用时,要遵循最左原则),唯一索引(字段唯一)

结构分类

密集索引(聚集索引:聚集索引的叶子节点存放了索引的数据,索引当找到了叶子节点,也就获得了表的对于的数据;辅助索引的叶子节点只维护了主键id,还需要主键id回表查找)和稀疏索引(辅助索引):

密集索引文件的每个索引码都对应一个索引值(该行数据存储在叶子节点上)

稀疏索引文件 只为索引码的某些值建立索引项

myisam是稀疏索引(需要回表)

innodb是有且仅有一个密集索引:如果主键被定义,该组件就是密集索引;如果没有被定义,该表的第一个非空唯一索引则为密集索引;

如果不满足以上条件,innodb内部会生产隐藏的主键(密集索引)

(稀疏索引)非主键索引存储相关键位和其对应的主件值,包含两次查询(回表);

覆盖索引的定义: 如果一个索引包含(或覆盖)所有需要查询的字段的值,称为‘覆盖索引’。即只需扫描索引而无须回表。 回表:先索引扫描,再通过ID去取索引中未能提供的数据,即为回表

总结:稀疏索引和密集索引的区别:稀疏索引的索引和数据是分开的,密集索引的数据和索引都存在叶子节点上

主要参数及配置文件

它的实现是在每一行数据上都隐藏那个了三个字段 db_row_id, db_trx_id(事务指针)当数据插入到该行,就会更新为当前事务id ,db_roll_ptr(回滚指针,指针指向最新被修改的undo日志)

mvcc(重要) 是在innodb的事务隔离级别为rc和rr的情况下可以使用,使用这个机制,降低了在并发环境下,不用加锁就可以实现多个事务并发读写。

实现原理:每条数据都维护了一个字段db_trx_id,存储着操作该数据的最新事务id,在数据被修改后,该条数据会被写入到undo文件,版本间的关联通过db_roll_ptr单向链表连接。在执行查询语句时,会根据执行的当前session生产快照记录 review[最小活跃事务id,最大活跃事务id],通过快照,当前数据及undo数据的db_trx_id执行比对的规则来找出符合条件的数据 实现可重复读事务,具体可看下图

redo已经被事务提交的数据

undo(存储未被提交的数据)(同一条数据,由db_roll_ptr单向链表连接)

数据和索引存储到一个文件。rmf 表结构存储到一个文件。

错误日志文件(show variable like 'log_error%';)

二进制日志 (包含ddl,dml语句,不包含查询语句)binglog

查询日志

慢查询日志

数据库优化

  • 主要优化的方向(1、减少cpu和磁盘间的io,提高数据命中,减少产生临时表)

  • 索引 索引创建的规则

1、字段较小的索引比索引长的好(索引字段如果比较大,会增加io的次数,一次加载索引到cpu较少)

2、较频繁的查询条件适合作为索引

3、频繁修改的字段不适合作为索引(因为每次增加,索引树都会产生裂变,产生io)

4、区分度低的数据不适合作为索引(效率低)

5、对于需要排序,分组的,使用索引(避免临时文件的产生)

临时表(cpu需要一段一段处理好的数据,存在临时表,处理完再发生给客户端)

  • 数据库优化的定位 1、开启慢查询日志 show variables like '%slow_query%';

开启慢查询日志 :set global slow_query_log=on;

设置慢查询时间:SET GLOBAL long_query_time = 1

开启日志后,符合慢查询时间条件的查询语句后存放到慢查询日志

使用mysql自带的mysqldumpslow统计慢查询情况

比价强大的分析慢查询日志工具 pt-query-digest pt-sumary可以查看服务器的信息;

pt-diskstats命令可以查询mysql的环境信息,包括引擎,磁盘开销,数据库的集群情况;

pt-query-digest 慢查询日志路径(统计索引慢查询的信息): 每条慢查询的信息,包括执行的次数,每次执行的时间,时间的占比,锁表的时间,每条语句的执行时间的分布图

主要看的是执行次数,执行时间,锁表时间,扫描的数据和发时数据的比row send 和row exam,这三个指标决定了系统的而整体性能

row examws是扫描的行数多,io开销大

对比row eaxam(加载到cpu的数据)和send(发送到客户端的数据) 判断语句的索引命中高不高

重点 关注的语句

1、查询次数多,查询时间长的语句

这条命令控制了统计的是慢查询日志的多少的信息

这条命令查询大表

确认了需要优化的语句(使用频繁,执行时间长的语句)

使用explain分析语句的执行计划和执行情况

说明:

id:id越大,越早执行;

select——type(了解) table

type列(重要)

小记,左关联查询的时候,左边是驱动表,右表是被驱动表,需要做左表进行全表扫描,原则上,小表当驱动表,这样,扫描的时长就降低,每条右表,都要拿去匹配左表

key_len 越小越好()

(重要)

通过重要的指标(id,type,extra,key,key_len)级别可以清楚执行的效率

建立索引的原则

尽量使用复合索引,因为数据库在执行的时候,只会选择多个索引中的一个,而复合索引,可能会更精确查询

对于group by ,order需要建立索引,或者在服务器处理数据,减少数据库出现中间表

在并发的环境下,由于大量的锁,导致系统性能急剧下降

复杂的join语句,所需要锁定的资源越来越多,导致系统变慢。

可以将复杂的sql改为简单的sql,通过返回到服务器,再处理数据

复合索引需要遵循最左原则

索引失效的语句

日常工作的优化:

加索引,避免返回不必要的主句数据,适当分批进行,优化sql的结构,分库分表,读写分离

innodb使用的场景:

对事务有要求,数据修改频繁的场景

myisam:

没有事务的业务,插叙频繁的场景

常见的问题:

myisam和innodb的区别{使用的聚集索引和非聚集索引;锁的控制粒度不同;支持事务;是否有外键}

数据库事务的四大特性:原子性,一致性,隔离性,持久性

innodb的可重复度隔离级别下,如何避免幻读

当前读:查询语句增加共享锁或独占锁,和删除,增加,修改操作

快照读:读的有可能是旧版本的数据,不一定是最新版本

mvcc读:mvcc全称是multi version concurrent control(多版本并发控制)。mysql把每个操作都定义成一个事务,每开启一个事务,系统的事务版本号自动递增。每行记录都有两个隐藏列:创建版本号和删除版本号

blog.csdn.net/weixin_4217…

rc,rr级别下的innodb的非阻塞读如何实现

RR 重复读 下,大事务嵌套几个小事务,第一个小事务写操作提交后,后面的小事务不能读取到第一个小事务提交的内容;

RC 读已提交 下,大事务嵌套几个小事务,第一个小事务写操作提交后,后面的小事务可以读取到第一个小事务提交的内容;

事务总能够读取到自己写入(update /insert /delete)的行记录 RC下,快照读总是能读到最新的行数据快照,当然,必须是已提交事务写入的 RR下,某个事务首次read记录的时间为T,未来不会读取到T时间之后已提交事务写入的记录,以保证连续相同的read读到相同的结果集

系统优化实践

日志模块的优化(分页的优化,总数优化,查询条件优化,读写分离优化,内存优化)

用中间件实现数据库集群,读写分离

分表

分区,分片

区:将一张表的文件,分成多个文件存储,如果一个磁盘放不下,可以存储到其他的磁盘 表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。

优点:

1、单表可以存储跟多的数据;

2、借助where语句,根据分区找到对应的数据,提高查询的效率

缺点:

1、一个表只能做1024个分区

分区的类型: range分区:按某字段的列值,大小的范围分到不同的区

list分区:按某字段的离散值,分到不同的区

hash分区:按用户提供的hash计算值分到对应的区域

key分区:?

总结:RANGE,LIST,HASH分区要求分区键必须是INT类型,或者通过表达式返回INT类型。但KEY分区的时候,可以使用其他类型的列(BLOB,TEXT类型除外)作为分区键

分区侧重提高读写性能,分表侧重提高并发性能。两者不冲突,可以配合使用

:就是分库+分表,属于水平切分,将表中数据按照某种规则放到多个库中,既分表又分库,就相当于原先一个库中的一个表,现在放到了好多个表里面,然后这好多个表又分散到了好多个库中。

分片的规则:

1、不分就不分,对于1000万以内的表,不建议分片,通过合适的索引,读写分离等方式,可以更好地解决性能问题。

  1. 分片数量不是越多越好,并且尽量均匀分布在多个存储节点上,只在必要的时候进行扩容,增加分片数量。

  2. 分片键不能为空,不能修改,所以要选择表中中最常用且不变的字段。

  3. 分片键选择时尽量做到可以将事务控制在分片范围内,可以避免出现跨分片的操作。

分片的选择是取决于最频繁的查询 SQL 的条件。找出每个表最频繁的 SQL,分析其查询条件,以及相互的关系比较准确的选择每个表的分片策略。

分片需要解决的问题: 事务问题 第一种由应用程序和数据库共同控制,将一个跨多个数据库的分布式事务分拆成多个仅处于单个数据库上面的小事务,并通过应用程序来总控各个小事务。

跨节点Join的问题:

1、求查询实现关联查询

2、如果频次较高,可以考虑添加一张关联表,规避掉join操作,空间换时间。在交易时直接将记录插入关联表,即可在查询时查询关联表获得想要的结果。

3、点的count,order by,group by以及聚合函数问题 获取的数据先放到服务器 但如果结果集很大,对应用程序内存的消耗是一个问题。 如果你的应用中包含大量的此类分析及聚合操作,考虑是否你对系统类型判断有误,是OLAP而非OLTP系统。对于OLAP系统不推荐使用MySQL更不推荐使用DRDS分布式数据库存储。 ID问题 一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键生成机制。 比较常见的ID解决方案是应用生成UUID

优点、提高读写性能和并发性能

缺点:

架构级别的优化

使用redis缓存

使用全文索引

使用消息队列

分表分库