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 #减多少

浙公网安备 33010602011771号