提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
视图是一种 虚拟表 ,本身是 不具有数据 的,占用很少的内存空间,它是 SQL 中的一个重要概念。
视图建立在已有表的基础上, 视图赖以建立的这些表称为基表。
视图的创建和删除只影响视图本身,不影响对应的基表。但是当对视图中的数据进行增加、删除和修改操作时,数据表中的数据会相应地发生变化,反之亦然。
向视图提供数据内容的语句为 SELECT 语句, 可以将视图理解为存储起来的 SELECT 语句
视图,是向用户提供基表数据的另一种表现形式。通常情况下,小型项目的数据库可以不使用视图,但是在大型项目中,以及数据表比较复杂的情况下,视图的价值就凸显出来了,它可以帮助我们把经常查询的结果集放到虚拟表中,提升使用效率。理解和使用起来都非常方便。
那服务器进程对客户端进程发送的请求做了什么处理,才能产生最后的处理结果呢?这里以查询请求为


第1层:连接层
系统(客户端)访问 MySQL 服务器前,做的第一件事就是建立 TCP 连接。
经过三次握手建立连接成功后, MySQL 服务器对 TCP 传输过来的账号密码做身份认证、权限获取。
TCP 连接收到请求后,必须要分配给一个线程专门与这个客户端的交互。所以还会有个线程池,去走后面的流程。每一个连接从线程池中获取线程,省去了创建和销毁线程的开销。
第2层:服务层
SQL Interface: SQL接口
Parser: 解析器
Optimizer: 查询优化器
Caches & Buffers: 查询缓存组件
第3层:引擎层
存储层

InnoDB 引擎:具备外键支持功能的事务存储引擎
MyISAM 引擎:主要的非事务处理存储引擎
Memory 引擎:置于内存的表
存储限制
事务安全
锁机制
哈希索引
索引缓存
支持外键
聚簇索引

一个B+树的节点其实可以分成好多层,规定最下边的那层,也就是存放我们用户记录的那层为第 0 层,之后依次往上加。之前我们做了一个非常极端的假设:存放用户记录的页 最多存放3条记录 ,存放目录项记录的页 最多存放4条记录 。其实真实环境中一个页存放的记录数量是非常大的,假设所有存放用户记录的叶子节点代表的数据页可以存放 100条用户记录 ,所有存放目录项- 记录的内节点代表的数据页可以存放 1000条目录项记录 ,那么:
你的表里能存放 100000000000 条记录吗?所以一般情况下,我们 用到的B+树都不会超过4层 ,那我们通过主键值去查找某条记录最多只需要做4个页面内的查找(查找3个目录项页和一个用户记录页),又因为在每个页面内有所谓的 Page Directory (页目录),所以在页面内也可以通过 二分法 实现快速定位记录。
聚簇索引
使用记录主键值的大小进行记录和页的排序,这包括三个方面的含义:
B+树的 叶子节点 存储的是完整的用户记录。
优点:
缺点:
二级索引(辅助索引、非聚簇索引)

回表
为什么我们还需要一次 回表 操作呢?直接把完整的用户记录放到叶子节点不OK吗
联合索引
不适合范围查找
实际上mongDB使用的就是B树索引,只不过MYSQL引擎没有使用B树木索引
B+树索引和B树索引最大的区别就在于,B+树的数据只存储在叶子节点,而B树索引数据会存储在叶子节点和非叶子节点。 一个页的默认大小是16KB,我认为如果非叶子节点如果存储数据,那么会降低检索叶子节点的效率,因为检索是从根节点开始,如果一次检索出的数据更多,检索定位到叶子节点的速度就快。而B树的非叶子节点会存储数据,索引有非叶子定位叶子节点的效率相对于较慢,但是这个又涉及到概率问题,如果检索的数据正好在非叶子节点中,那么只需要两次IO,最夸张的情况下,可能在根节点就能检索出数据了,也就是一次IO就可以了,但是B+树比较稳定,一般只需要3次IO,B树的话,看情况,运气好1次,不好就会很多次,因为B树的结构会更深。相比来说B+树更好
降序索引
隐藏索引
字段的数值有唯一性的限制
频繁作为 WHERE 查询条件的字段
经常 GROUP BY 和 ORDER BY 的列
UPDATE、DELETE 的 WHERE 条件列
.DISTINCT 字段需要创建索引
多表 JOIN 连接操作时,创建索引注意事项
使用列的类型小的创建索引
使用字符串前缀创建索引
区分度高(散列性高)的列适合作为索引
使用最频繁的列放到联合索引的左侧(最左前缀原则)
在多个字段都要创建索引的情况下,联合索引优于单值索引
限制索引的数目
数据库服务器的优化步骤
首先观察服务器状态,是否存在 周期性变动,是不是业务活动造成流量变大,如果是可以考虑使用缓存解决
如果不是,开启慢查询,定位到慢sql,找到满sql后开始分析

如果问题,没有解决,就得考虑【读写分离】、【分库分表】了
查看系统性能参数
统计SQL的查询成本:last_query_cost





定位执行慢的 SQL:慢查询日志
开启slow_query_log

修改long_query_time阈值



查看 SQL 执行成本:SHOW PROFILE




分析查询语句:EXPLAIN

分析优化器执行计划:trace
全值匹配我最爱(联合索引)

最佳左前缀法则

主键插入顺序


计算、函数、类型转换(自动或手动)导致索引失效
类型转换导致索引失效

范围条件右边的列索引失效


不等于(!= 或者<>)索引失效
is null可以使用索引,is not null无法使用索引
like以通配符%开头索引失效
OR 前后存在非索引的列,索引失效
数据库和表的字符集统一使用utf8mb4







利用索引列,通过where减少回表操作





问:在 MySQL 中统计数据表的行数,可以使用三种方式: SELECT COUNT(*) 、 SELECT COUNT(1) 和 SELECT COUNT(具体字段) ,使用这三者之间的查询效率是怎样的?




第一范式:确保表中每一列数据的原子性,不可再分!(必须要有主键)
第二范式:在满足第一范式的基础上,确保列数据要跟主键关联,不能出现部分依赖。
第三范式设计表:再满足第二范式的基础上,保证每一列数据都要跟主键直接关联,不能出现传递依赖。


我们需要调优的对象是整个数据库管理系统,它不仅包括 SQL 查询,还包括数据库的部署配置、架构等。从这个角度来说,我们思考的维度就不仅仅局限在 SQL 优化上了。通过如下的步骤我们进行梳理:
第1步:选择适合的 DBMS

第2步:优化表设计

第3步:优化逻辑查询

第4步:优化物理查询

第5步:使用 Redis 或 Memcached 作为缓存

第6步:库级优化










拆分表:冷热数据分离

增加中间表


增加冗余字段

优化数据类型



优化插入记录的速度




使用非空约束



































一秒刷新一次















从数据操作的类型划分:读锁、写锁








从数据操作的粒度划分:表级锁、页级锁、行锁





























































REPEATABLE READ 只在第一次进行普通SELECT操作前生成一个ReadView,之后的查询操作都重复使用这个ReadView就好了。



Slave 会从 Master 读取 binlog 来进行数据同步。









在执行更新语句过程,会记录redo log与binlog两块日志,以基本的事务为单位,redo log在事务执行过程中可以不断写入,而binlog只有在提交事务时才写入,所以redo log与binlog的 写入时机 不一样。





两阶段提交解决的是,由于主库宕机,导致binlog丢失,但是redo日志已经持久化到磁盘,此时就会出现主从不一致的情况







如何解决一致性问题?






垂直(纵向)切分:按照不同的表(或者Schema)来切分到不同的数据库(主机)之上

水平(横向)切分:根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库

MyCat原理中最重要的一个动词就是 “拦截”, 它拦截了用户发送过来的SQL语句, 首先对SQL语句做一些特定的分析,如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL语句发往后端的真实数据库,并将返回的结果做适当处理,最终再返回给用户,如图所示。

在图中,user表被分为三个分片节点dn1、dn2、dn3, 他们分布式在三个MySQL Server(dataHost)上,因此可以使用1-N台服务器来分片,分片规则(sharding rule)为典型的字符串枚举分片规则, 一个规则的定义是分片字段+分片函数。这里的分片字段为 status,分片函数则为字符串枚举方式。
MyCat收到一条SQL语句时,首先解析SQL语句涉及到的表,接着查看此表的定义,如果该表存在分片规则,则获取SQL语句里分片字段的值,并匹配分片函数,得到该SQL语句对应的分片列表,然后将SQL语句发送到相应的分片去执行,最后处理所有分片返回的数据并返回给客户端。以"select * from user where status=‘0’" 为例, 查找 status=‘0’ ,按照分片函数, ‘0’ 值存放在dn1,于是SQL语句被发送到第一个节点中执行, 然后再将查询的结果返回给用户。如果发送的SQL语句为 “select * from user where status in (‘0’,‘1’)” , 那么SQL语句会被发送到dn1,dn2对应的主机上执行, 然后将结果集合并后输出给用户。
server.xml<?xml version="1.0" encoding="UTF-8"?>
<!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License. - You
may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - Unless required by applicable law or agreed to in writing, software -
distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
License for the specific language governing permissions and - limitations
under the License. -->
<!DOCTYPE mycat:server SYSTEM "server.dtd">
<mycat:server xmlns:mycat="http://io.mycat/">
<system>
<property name="nonePasswordLogin">0</property> <!-- 0为需要密码登陆、1为不需要密码登陆 ,默认为0,设置为1则需要指定默认账户-->
<property name="useHandshakeV10">1</property>
<property name="useSqlStat">0</property> <!-- 1为开启实时统计、0为关闭 -->
<property name="useGlobleTableCheck">0</property> <!-- 1为开启全加班一致性检测、0为关闭 -->
<property name="sqlExecuteTimeout">300</property> <!-- SQL 执行超时 单位:秒-->
<property name="sequnceHandlerType">2</property>
<!--<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>-->
<!--必须带有MYCATSEQ_或者 mycatseq_进入序列匹配流程 注意MYCATSEQ_有空格的情况-->
<property name="sequnceHandlerPattern">(?:(\s*next\s+value\s+for\s*MYCATSEQ_(\w+))(,|\)|\s)*)+</property>
<property name="subqueryRelationshipCheck">false</property> <!-- 子查询中存在关联查询的情况下,检查关联字段中是否有分片字段 .默认 false -->
<!-- <property name="useCompression">1</property>--> <!--1为开启mysql压缩协议-->
<!-- <property name="fakeMySQLVersion">5.6.20</property>--> <!--设置模拟的MySQL版本号-->
<!-- <property name="processorBufferChunk">40960</property> -->
<!--
<property name="processors">1</property>
<property name="processorExecutor">32</property>
-->
<!--默认为type 0: DirectByteBufferPool | type 1 ByteBufferArena | type 2 NettyBufferPool -->
<property name="processorBufferPoolType">0</property>
<!--默认是65535 64K 用于sql解析时最大文本长度 -->
<!--<property name="maxStringLiteralLength">65535</property>-->
<!--<property name="sequnceHandlerType">0</property>-->
<!--<property name="backSocketNoDelay">1</property>-->
<!--<property name="frontSocketNoDelay">1</property>-->
<!--<property name="processorExecutor">16</property>-->
<!--
<property name="serverPort">8066</property> <property name="managerPort">9066</property>
<property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
<property name="dataNodeIdleCheckPeriod">300000</property> 5 * 60 * 1000L; //连接空闲检查
<property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
<!--分布式事务开关,0为不过滤分布式事务,1为过滤分布式事务(如果分布式事务内只涉及全局表,则不过滤),2为不过滤分布式事务,但是记录分布式事务日志-->
<property name="handleDistributedTransactions">0</property>
<!--
off heap for merge/order/group/limit 1开启 0关闭
-->
<property name="useOffHeapForMerge">0</property>
<!--
单位为m
-->
<property name="memoryPageSize">64k</property>
<!--
单位为k
-->
<property name="spillsFileBufferSize">1k</property>
<property name="useStreamOutput">0</property>
<!--
单位为m
-->
<property name="systemReserveMemorySize">384m</property>
<!--是否采用zookeeper协调切换 -->
<property name="useZKSwitch">false</property>
<!-- XA Recovery Log日志路径 -->
<!--<property name="XARecoveryLogBaseDir">./</property>-->
<!-- XA Recovery Log日志名称 -->
<!--<property name="XARecoveryLogBaseName">tmlog</property>-->
<!--如果为 true的话 严格遵守隔离级别,不会在仅仅只有select语句的时候在事务中切换连接-->
<property name="strictTxIsolation">false</property>
<property name="useZKSwitch">true</property>
</system>
<!-- 全局SQL防火墙设置 -->
<!--白名单可以使用通配符%或着*-->
<!--例如<host host="127.0.0.*" user="root"/>-->
<!--例如<host host="127.0.*" user="root"/>-->
<!--例如<host host="127.*" user="root"/>-->
<!--例如<host host="1*7.*" user="root"/>-->
<!--这些配置情况下对于127.0.0.1都能以root账户登录-->
<!--
<firewall>
<whitehost>
<host host="1*7.0.0.*" user="root"/>
</whitehost>
<blacklist check="false">
</blacklist>
</firewall>
-->
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">TESTDB</property>
<!-- 表级 DML 权限设置 -->
<!--
<privileges check="false">
<schema name="TESTDB" dml="0110" >
<table name="tb01" dml="0000"></table>
<table name="tb02" dml="1111"></table>
</schema>
</privileges>
-->
</user>
<user name="user">
<property name="password">user</property>
<property name="schemas">TESTDB</property>
<property name="readOnly">true</property>
</user>
</mycat:server>
schema.xml
-
name: 定义逻辑表的表名
-
dataNode:这个逻辑表都在哪些节点上

-
rule:指定逻辑表的分片规则的名字, 规则的名字是在rule.xml文件中定义的, 必须与tableRule标签中name属性对应。



-

-
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
<schema name="TESTDB" checkSQLschema="true" sqlMaxLimit="100">
<!-- auto sharding by id (long) -->
<table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />
<!-- <table name="oc_call" primaryKey="ID" dataNode="dn1$0-743" rule="latest-month-calldate"
/> -->
</schema>
<!-- <dataNode name="dn1$0-743" dataHost="localhost1" database="db$0-743"
/> -->
<dataNode name="dn1" dataHost="localhost1" database="db1" />
<dataNode name="dn2" dataHost="localhost1" database="db2" />
<dataNode name="dn3" dataHost="localhost1" database="db3" />
<!--<dataNode name="dn4" dataHost="sequoiadb1" database="SAMPLE" />
<dataNode name="jdbc_dn1" dataHost="jdbchost" database="db1" />
<dataNode name="jdbc_dn2" dataHost="jdbchost" database="db2" />
<dataNode name="jdbc_dn3" dataHost="jdbchost" database="db3" /> -->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="localhost:3306" user="root"
password="123456">
</writeHost>
<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
</dataHost>
<!--
<dataHost name="sequoiadb1" maxCon="1000" minCon="1" balance="0" dbType="sequoiadb" dbDriver="jdbc">
<heartbeat> </heartbeat>
<writeHost host="hostM1" url="sequoiadb://1426587161.dbaas.sequoialab.net:11920/SAMPLE" user="jifeng" password="jifeng"></writeHost>
</dataHost>
<dataHost name="oracle1" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="oracle" dbDriver="jdbc"> <heartbeat>select 1 from dual</heartbeat>
<connectionInitSql>alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss'</connectionInitSql>
<writeHost host="hostM1" url="jdbc:oracle:thin:@127.0.0.1:1521:nange" user="base" password="123456" > </writeHost> </dataHost>
<dataHost name="jdbchost" maxCon="1000" minCon="1" balance="0" writeType="0" dbType="mongodb" dbDriver="jdbc">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM" url="mongodb://192.168.0.99/test" user="admin" password="123456" ></writeHost> </dataHost>
<dataHost name="sparksql" maxCon="1000" minCon="1" balance="0" dbType="spark" dbDriver="jdbc">
<heartbeat> </heartbeat>
<writeHost host="hostM1" url="jdbc:hive2://feng01:10000" user="jifeng" password="jifeng"></writeHost> </dataHost> -->
<!-- <dataHost name="jdbchost" maxCon="1000" minCon="10" balance="0" dbType="mysql"
dbDriver="jdbc"> <heartbeat>select user()</heartbeat> <writeHost host="hostM1"
url="jdbc:mysql://localhost:3306" user="root" password="123456"> </writeHost>
</dataHost> -->
</mycat:schema>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
MyCat分片
- 垂直分片
- 水平分片
垂直分片和水平分片就是解决数据分片的两种逻辑,在分库分表工作中通常都是二者都有,对于不同的业务,比如订单表和用户表,就可以才用垂直分片,即放在不同的数据节点,而水平分片是对同一个表的数据分片,把一个表的不同的数据放在不同的数据库上
分片解决数据库磁盘的压力和数据查询压力
垂直分片是一种业务纵向考虑的
水平分片是横向考虑的
分片规则
分片规则其实是对水平分片来说的
- 取模分片

- 范围分片

- 枚举分片


- 范围求模算法
该算法为先进行范围分片, 计算出分片组 , 再进行组内求模。
优点: 综合了范围分片和求模分片的优点。 分片组内使用求模可以保证组内的数据分布比较均匀,分片组之间采用范围分片可以兼顾范围分片的特点。
缺点: 在数据范围时固定值(非递增值)时,存在不方便扩展的情况,例如将 dataNode Group
size 从 2 扩展为 4 时,需要进行数据迁移才能完成 ;


- 固定分片hash算法(类似于redis的hash槽)
该算法类似于十进制的求模运算,但是为二进制的操作,例如,取 id 的二进制低 10 位 与1111111111 进行位 & 运算

优点: 这种策略比较灵活,可以均匀分配也可以非均匀分配,各节点的分配比例和容量大小由
partitionCount和partitionLength两个参数决定
缺点:和取模分片类似。
- 取模范围算法
该算法先进行取模,然后根据取模值所属范围进行分片。
优点:可以自主决定取模后数据的节点分布
缺点:dataNode 划分节点是事先建好的,需要扩展时比较麻烦。


- 字符串hash求模范围算法
与取模范围算法类似, 该算法支持数值、符号、字母取模,首先截取长度为 prefixLength 的子
串,在对子串中每一个字符的 ASCII 码求和,然后对求和值进行取模运算
(sum%patternValue),就可以计算出子串的分片数。
优点:可以自主决定取模后数据的节点分布
缺点:dataNode 划分节点是事先建好的,需要扩展时比较麻烦。


-
应用指定算法
由运行阶段由应用自主决定路由到那个分片 , 直接根据字符子串(必须是数字)计算分片号 , 配置如下 :



-
字符串hash解析算法
截取字符串中的指定位置的子字符串, 进行hash算法, 算出分片 , 配置如下:


- 一致性hash算法
一致性Hash算法有效的解决了分布式数据的拓容问题 , 配置如下:



mycat性能监控工具

Mycat读写分离,以及banlance机制
balance=“0” : 不开启读写分离机制 , 所有读操作都发送到当前可用的writeHost上. (从库只是数据备份的作用)
balance=“1” : 全部的readHost 与 stand by writeHost (备用的writeHost) 都参与 select 语句的负载均衡,简而言之,就是采用双主双从模式(M1 --> S1 , M2 --> S2, 正常情况下, M2,S1,S2 都参与 select 语句的负载均衡。);
balance=“2” : 所有的读写操作都随机在writeHost , readHost上分发
balance=“3” : 所有的读请求随机分发到writeHost对应的readHost上执行, writeHost不负担 读压力 ;balance=3 只在MyCat1.4 之后生效 .
一主一从和双主双从
一主一从:master写库宕机,salve读库其实不会切换为主库
双主双从:解决单主库宕机的问题

mycat集群

主从同步不一致
-
MySQL主从不同步情况
-
1、网络的延迟
由于mysql主从复制是基于binlog的一种异步复制通过网络传送binlog文件,理所当然网络延迟是主从不同步的绝大多数的原因,特别是跨机房的数据同步出现这种几率非常的大,所以做读写分离,注意从业务层进行前期设计。
-
2、主从两台机器的负载不一致
由于mysql主从复制是主数据库上面启动1个io线程,而从上面启动1个sql线程和1个io线程,当中任何一台机器的负载很高,忙不过来,导致其中的任何一个线程出现资源不足,都将出现主从不一致的情况。
-
3、max_allowed_packet设置不一致
主数据库上面设置的max_allowed_packet比从数据库大,当一个大的sql语句,能在主数据库上面执行完毕,从数据库上面设置过小,无法执行,导致的主从不一致。
-
4、自增键不一致
key自增键开始的键值跟自增步长设置不一致引起的主从不一致。
-
5、同步参数设置问题
mysql异常宕机情况下,如果未设置sync_binlog=1或者innodb_flush_log_at_trx_commit=1很有可能出现binlog或者relaylog文件出现损坏,导致主从不一致。
-
6、自身bug
mysql本身的bug引起的主从不同步
-
7、版本不一致
特别是高版本是主,低版本为从的情况下,主数据库上面支持的功能,从数据库上面不支持该功能。
1.停止slave从节点
stop slave;
2.跳过一步错误,后面的数字可变
set global sql_slave_skip_counter =1;
3.开启slave
start slave;
4.查看slave状态
show slave status\G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
ok,现在主从同步状态正常了。。。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
3、使用第三方工具如pt-table-sync





-
相关阅读:
字符编码个人理解
搭建自己的文件服务器
矩阵乘法通过缓存命中率提升运算效率
JavaScript的作用域和作用域链
Google I/O 2023 - Dart 3 发布,快来看看有什么更新吧
[附源码]计算机毕业设计JAVA校园失物招领平台
maven_0
ARM pwn 入门 (3)
持续集成和持续部署
mysql中的存储过程
-
原文地址:https://blog.csdn.net/m0_45364328/article/details/126569431