Mysql主从复制的工作原理和流程及redis部分命令

Mysql主从复制的工作原理和流程

基本原理流程,3个线程以及之间的关联

主:binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中;

从:io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进自己的relay log中;

从:sql执行线程——执行relay log中的语句

Binary log:主数据库的二进制日志

Relay log:从服务器的中继日志

第一步:master在每个事务更新数据完成之前,将该操作记录串行地写入到binlog文件中。

第二步:salve开启一个I/O Thread,该线程在master打开一个普通连接,主要工作是binlog dump process。如果读取的进度已经跟上了master,就进入睡眠状态并等待master产生新的事件。I/O线程最终的目的是将这些事件写入到中继日志中。

第三步:SQL Thread会读取中继日志,并顺序执行该日志中的SQL事件,从而与主数据库中的数据保持一致。

读写分离时的解决方案

方案一

使用mysql-proxy代理

优点:直接实现读写分离和负载均衡,不用修改代码,master和slave用一样的帐号,mysql官方不建议实际生产中使用

缺点:降低性能, 不支持事务

方案二

使用AbstractRoutingDataSource+aop+annotation在dao层决定数据源。
如果采用了mybatis, 可以将读写分离放在ORM层,比如mybatis可以通过mybatis plugin拦截sql语句,所有的insert/update/delete都访问master库,所有的select 都访问salve库,这样对于dao层都是透明。 plugin实现时可以通过注解或者分析语句是读写方法来选定主从库。不过这样依然有一个问题, 也就是不支持事务, 所以我们还需要重写一下DataSourceTransactionManager, 将read-only的事务扔进读库, 其余的有读有写的扔进写库。

方案三

使用AbstractRoutingDataSource+aop+annotation在service层决定数据源,可以支持事务.

缺点:类内部方法通过this.xx()方式相互调用时,aop不会进行拦截,需进行特殊处理。

执行计划

id

select 查询的序列号,标识执行的顺序,表示查询中执行select子句或操作表的顺序

  • Id相同,执行顺序由上至下
  • Id不同,id值越大,优先级越高,越先被执行
  • 如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行

select_type

​ 查询的类型,主要是用于区别普通查询、联合查询、子查询等的复杂查询

类型 描述
SIMPLE 简单的 select 查询,查询中不包含子查询或者UNION
PRIMARY 查询中若包含任何复杂的子部分,最外层查询则被标记为
SUBQUERY 在SELECT或WHERE列表中包含了子查询
DERIVED 在FROM列表中包含的子查询被标记为DERIVED(衍生)MySQL会递归执行这些子查询, 把结果放在临时表里。
UNION 若第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
UNION RESULT 从UNION表获取结果的SELECT

table

使用的表的名字

type(最重要)

访问类型

system > const > eq_ref > ref > range > index > ALL

system 系统表,少量数据,往往不需要进行磁盘IO
const 常量连接
eq_ref 主键索引(primary key)或者非空唯一索引(unique not null)等值扫描
ref 非主键非唯一索引等值扫描
range 范围扫描
index 索引树扫描
ALL 全表扫描(full table scan)
总结:

各类扫描类型的要点是:
system 最快:不进行磁盘 IO
const:PK 或者 unique 上的等值查询
eq_ref:PK 或者 unique 上的 join 查询,等值匹配,对于前表的每一行,后表只有一行命中
ref:非唯一索引,等值匹配,可能有多行命中
range:索引上的范围扫描,例如:between、in、>
index:索引上的全集扫描,例如:InnoDB 的 count
ALL 最慢:全表扫描

possible_keys字段

表示查询过程中有可能用到的索引。

key字段

实际使用的索引,如果为NULL,则没有使用索引。

key_len字段

表示索引中使用的字节数。

  • key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
  • 允许为空的字段会多占用一个字节的空间

字符类型的key_len

  • 不同的字符编码,每个字符占用的字节数不同,latin类型的每个字符占用1个字节,gbk是2字节,utf8类型的每个字符占用3个字节,utf8mb4类型的每个字符占用4个字节
  • char和varchar类型的差异,varchar类型需要额外的2个字节记录实际字符占用的空间。NULL允许为空占用一个字节

key_len的计算公式

varchar(n)变长字段+允许Null=n*(utf8mb4=4,utf8=3,gbk=2,latin1=1)+1(NULL)+2(变长字段)

注意:datetime在5.5版本占用8个字节,在5.6版本占用5个字节。

组合索引的key_len

复合索引有最左前缀的特性,如果符合索引能全部使用上,则是符合索引字段的索引长度之和,这也可以用来判定复合索引是否部分使用,还是全部使用。

int number = 10;
namespace wd
{
    int number = 20;
    
    class Test
    {
      public:
        void print(int number)
        {
            cout << "number = " << number << endl;
            
        }
    };
    
}

redis命令

select index (select 1) #数据库的切换
dbsize #查看redis某个数据库的大小
keys * #查看当前数据下key值(匹配任意个字符)
keys k? #匹配以k开头的
del key值(del k1) #删除某个key 如果成功,会返回1
move key值  index #移动某个key值到里另外一个数据
exists keys #查看某个key值是否存在
type key (type 3k)#查看变量类型,类似于linux下的file
expire key值 num(一个数字,秒数为单位) #设置过期时间
Ttl key值 #查看是否过期 -2为过期 -1为永不过期 

常用数据类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

string

set key value(set p1 100) #设定指定key的值
get key(get p1) #获取定义key值
mset key value...#可以一次性设置多个值
mget keys...    # 一次获取多个
getrange keys start end #类似于substr(按照数组顺序开始)
getrange keys 0 -1 #-1是倒数第一个 -2 是倒数第二个 同理 
setrange keys offset value#用value从offset位置开始覆盖
getset key value #将老的值返回,然后set新值
setex keys seconds value # 改变keys的值,同时设置过期时间,过期了就会ttl返回-2
incr keys #加一
incrby keys value #对key值加多少
decr keys #减一
decrby keys value #减多少
posted @ 2022-04-26 20:29  Fancele  阅读(98)  评论(0)    收藏  举报