MYSQL高级:
MySql架构演变,这个很重要,软件的环境是如何从单应用算法极致优化的方向,到分布式的进化,这个时代,就会淘汰好多单体应用的coder,比如我自己...哈哈哈哈
1.0时代:单机单库 单应用,单数据库.快速,方便.好维护. 并发量小,拓展性差,数据量大无法承受,数据库崩溃直接导致数据丢失.运算能力差
2.0主从复制: 一个主数据库,多辅助数据库,主库崩溃,从库立即顶上,保持可用性,进行读写分离,保证性能平均,也有缺点.数据量大的问题还是没有解决.主从复制数据是一样.写入的操作还是比较慢,因为只有一个主库可以写入,然后同步到从库.其余都是查的从库,大量insert 主从复制就不行了
3.0分库分表:将主从复制进行分布式,但每个主从各负责整体应用数据库的一部分.比如A表300条数据,可在三个分布式进行存储,A分布100条,B分布100条,C分布100条,也可将A表直接存在一个分布下.B表存在另一个分布下.提高整体应用存储能力,但也有一个新的问题.这些数据库如何保持一致性?如何通讯?
4.0云数据库 不再有本地数据库,将数据库做为服务, 我们使用服务接口,云服务商来决定数据如何存储和存储在哪.这是一个趋势,云生态替我们解决了很多成本问题.
MySql架构:
也就是一条sql语句的执行流程
客户层:
客户连接器:JDBC等连接的.
服务层:
连接池:与客户层连接的直接层次.提供线程池等,使用线程池会将性能提升3倍.读写会提升60倍.
管理工具:控制和管理数据库的工具
SQL接口:DML,DDL等接受sql语句
parser 解析器:解析SQL语句的模组,分为语法分析和词法分析,先解析词,后解析语法.
optimizer 查询优化器:解析后,交给优化器,负责提供执行计划,选出最佳的计划来进行执行.
优化器的例子:
1select根据where进行选取筛选.
2select根据字段进行属性投影,选出需要的字段,不全拿
3:把上面两步合起来展示
缓存:将表、查询、引擎进行缓存,如果缓存符合,那么不用直接去文件存储去获取了就
存储引擎层:
关键词:可插拔 可以修改源码达到自己的目的(太高大了)
服务层与文件系统衔接的层,根据不同的存储引擎有着不同的存储机制.
系统文件层:
存储数据、日志、配置.是数据库数据的最终归宿
日志:
错误日志
默认开启.show variables like %log_err% 查询错误文件的存储位置..
通用查询日志
记录查询语句.使用show variables like '%general%'
二进制日志
记录更改的操作. 不记录select的所有操作.记录语句发生时间,执行时长.
show variables like '%log_bin%'
show variables like '%bin_log%' 更高级的二进制日志
show binary logs; 查看日志文件
慢查询日志:
记录所有执行时间超时(默认10s)的查询sql.
show varables like '%slow)query%'
show varables like '%long_query_time%'
set long_query_time = 5 设置超时时间.
配置文件:
数据文件:
数据的存储
db.opt 字符集和校验规则
frm meta信息 每个表都一个frm
myd myisam专用 存储data
myi myisam 存储索引
ibd、ibdata innoDb的存储data和索引 ibd独享表空间 ibdata共享表空间
ibdata1: 原始数据、undo
show varables like '%datadir%' 来查看数据存储的文件夹
mysql的详细执行流程:
1:客户端连接
通信机制:
全双工:发数据时也接收数据
半双工:某一时间点发或着接,不能同时
单工:只能发或者接,不能两者都行
show full processlist 查看当前连接的线程信息
id:线程ID,可以kill掉他
user:用户
host:客户端主机
db:操作哪个库
time:连接时间
command:当前用户正在执行的操作,query执行语句啦.createDB建库啦,execute 执行stmt啦
state:当前用户的状态 updating 正在修改 starting正在执行请求 closing table正在存储 Locked 锁住状态 Sending Data 正在select
info:当前执行的语句
2:查询缓存
缓存之前的查询结果,如果命中直接返回.只缓存sql语句和结果.只有sql完全相同才会命中缓存.
show variables like %query_cache%
show status like Qcahce%
不能缓存的情况
sql语句添加sql_no_cache
结果大于query_cache_limit
不确定的参数 now()
3:解析器->解析树->预处理->新解析树
4:查询优化器->执行计划
等价变换策略 将一些条件进行更直观转换
联合索引调整条件位置
函数优化
inno DB min函数只找索引最左边
inno DB max函数只找索引最右边
myisam引擎 count(*) 不需要计算,直接返回
limit 提前停止查询 拿到limit够的量就不继续遍历了(查询其实就是遍历存在磁盘的数据,只不过用特定的语法查询,就是sql)
in 会先排序,然后二分法查找数据,先把in里的参数排序,然后二分法快速查找
5:查询执行引擎->存储引擎->存储文件
1.如果开启查询缓存了,那么第一次查询放入缓存,第二次查询时就先去查缓存.只能是同一sql 参数都一样的.
6:返回结果
2.存储引擎是有一定的增量返回的,如果结果过多,那么引擎会进行一定的控制进行逐步返回.
MySQL的存储引擎:
负责与具体的存储系统进行交互,执行sql、拿出存储的文件,都是引擎的工作.
InnoDB:支持事物:提交、回滚、崩溃恢复、事物安全
MyISAM:不支持事物和外键,访问速度更快
Memory:速度极快,数据存储在内存,默认使用Hash索引.关闭既消失
Archive:归档类型引擎,只能支持insert和select
Csv:类似于表格型的格式存储,由于被格式限制,所以列不能为null,不支持索引和分区,适合数据传输
BlackHole:黑洞引擎,只进不出,insert的数据不会保存.但是会有insert记录,可以查询到
Federated:远程的数据库的表.本地表不保存数据,通过远程来返回,oracle的link机制.
MRG_MyISAM:一组MyISAM的表,结构相同,操作一个 对所有的表都生效.
InnoDB和MyISAM的对比:
1.事物和外键:
InnoDB支持,大量新增和更新,强调安全和数据完整
MyISAM不支持,高速的检索和存储.
2.锁机制:
InnoDB支持行级锁,可以锁定具体的一条记录,基于索引加锁.
MyISAM支持表级锁,表内所有数据都被锁定
3:索引结构
InnoDB聚集索引,索引和记录存储在一块,缓存索引也缓存记录
MyISAM索引和记录是分开的,所以查询较快.
4:并发处理能力:
MyISAM是表级锁,并发写入性能低下
InnoDB行级锁,大量新增性能较好,
相比下他们俩更新具体一条记录时,性能持平,比如库存控制,现在基本也不这么设计了,都是用消息中间件或者中间缓存来延迟更新数据库.减轻数据库的压力.
5:存储文件
InnoDB对应两个文件,一个.frm表结构文件,一个.idb数据文件
最大支持64TB
MyISAM多一个 一个.frm表结构文件,一个.MYD数据文件,一个.MYI索引文件.256TB最大存储(5.0以上)
应用场景:
MyISAM:高速查询、不需要事物、并发低、数据一致性要求低
InnoDB:数据安全、行级锁提高并发能力、事物控制、大量新增、提升服务器内存利用率.
普遍场景:推荐使用InnoDB
InnoDB存储引擎:
存储结构:
结构一.内存结构:
buffer pool缓存池:存放缓存和配置.
详细剖析:
1)管理机制:
1>free page 空闲page,未被使用
2>clean page 被使用page,但没有被修改
3>dirty page 脏页:被使用,被修改,与磁盘不一致
用三种链表结构来管理这三个page,
freelist->free page
flushlist->dirty page 脏页的 按修改时间排序.最早在后,先更新磁盘,寄存在lrulist中,但互不影响
lrulist -> 正在使用的 clean page 和 dirty page,以midpoint为中点,左面为new列表,存放经常访问的数据.占63%右面为old,存放不咋用的,要被清掉的.占37%
2)采用改进型LRU算法维护:
普通LRU:末尾淘汰法,新数据进入头,释放空间从末尾释放.
改进LRU:链表分为new和old的,添加不从头,而从中点插入,数据被访问了,那么就从中点开始左移,如果没怎么被访问,那么就会被挤压到中点右面,等待被释放.
每当有新的page数据放入缓存池,InnoDB先判断有没有足够的free page,如果有就删除free list中的数据,然后放到LRU,如果没有了,那么LRU末尾就会开始释放,够了再插进来.
3)配置参数
show variables like '%innodb_page_size%'page大小
show variables like '%innodb_old%' lru old的参数
show variables like '%innodb_buffer%' 查看所有参数
缓存池的存储模块嵌套关系buffer->instance->chunk ->page
buffer推荐占物理内存的60-80% instance按需增加数量, page微量调整
change buffer 写缓存:负责存储新增和更新的缓存,避免频繁的磁盘操作,先对比缓存池中已有数据,,然后更新的数据放这,闲置时再更新入磁盘.
占用buffer pool空间 默认占25%,最大允许50% 根据写入量进行调整.
show variables like '%innidb_change_buffer_max_size%' 查看当前cb占比
set global innodb_change_buffer_max_size = 占比数
这个有用啊,目前开发的应用就需要大量的新增和更新操作,innoDB符合要求,再配合将changebuffer缓冲区调高,增加写入缓冲的大小,可以提高写入性能.
如果更新记录时 记录在buffer pool存在 就直接在buffer pool修改 并成为dirdy page,需要磁盘操作.如果没存在, 那么就直接存在change buffer,省下一次磁盘IO,如果下次查询时,会先磁盘读取,然后与change buffer数据进行合并, 最终存储在bufferpool中.
(自我总结)就是尽量省下磁盘IO,因为磁盘的性能远不如内存性能快速,在高频使用的数据就主要放入内存中提供频繁的访问,而不常用的就持久化到磁盘存储.
change buffer 仅仅使用非唯一普通索引.带主键或者唯一索引的进行修改时,innoDB需要做校验,这样就避免不了磁盘IO,所以带主键的表必须要磁盘获取了.但也是放入缓冲池 buffer pool修改.不会有change buffer这一操作了.
log buffer日志缓存区:负责存储操作记录.存储一定数量更新到磁盘.也有计划更新到磁盘
redo、undo日志.一般为16M大小(默认不是),过大会影响崩溃恢复的能力.
记录引擎日志.记录dml的redo undo日志.
show variables like '%innodb_log%'
show variables like '%innodb_flush_log%'
写入磁盘策略 默认1
0:每隔1秒进行写日志和刷盘操作 流程:log buffer-> OScache ->DISK
1:事务提交 就刷盘,频繁操作.
2:事物提交 就写日志 每隔一秒刷盘(兼顾,推荐使用)
自适应hash索引:监控缓存池的索引使用情况,进行自动调整.
结构二.磁盘结构:
system tablespcaes系统表空间
show variables like '%innodb_data_file_path%'查看
innoDB Data Dictionary:
Doublewrite buffer:
show variables like '%innodb_doublewrite%'
脏页先写到这里的缓冲区,防止系统的磁盘出现问题,写入速度也较快.
Undo Logs:
撤销日志.记录一些我们的一些操作,在必要时可以进行回滚.
File-Per-Table-Tbablespaces独立表空间
show variables like '%innodb_data_file_pre_table%'查看
General Tablespaces 通用表空间
create tablespace {name} add datafile '{name}.ibd' engine innoDB创建表空间 并使用innoDB引擎
Undo Tablespaces 回滚表空间
5.7与8.0的改变:
磁盘存储结构更改:
删除了表结构在系统表空间的存储.和frm存储有重叠,所以去掉了
8.0的系统表空间只保留了change buffer
doublewrite 单独分出
undo日志和undo表空间合并.
临时表空间细化区分 分为了全局和会话
innoDB的后台线程:
master thread 主线程:
调度其他三个线程,通过调用其他线程来实现工作,主线程不会被阻塞,如果有关闭的线程,那么该线程的工作还是主线程来做.内部有两个主处理,每隔一秒和每隔十秒
一秒的操作:
刷新日志缓冲区到磁盘
合并change buffer 根据IO读写压力决定是否操作
刷新脏页. 根据脏页比例, 达到75%再操作. show varables like '%innodb_max_dirty_pages_pct%' 查看百分比
show varables like '%innodb_io_capacity%' 查看可刷新写入多少页(page块)
十秒的操作:
脏页刷新到磁盘,没有限制了,必须做
合并change buffer 直接做
刷新日志缓冲到磁盘
删除无用的undo页
show varables like '%innodb_purge_batch_size%' 查看删除无用undo一次的数量
IO thread AIO机制: 10个线程
read负责读取操作,从磁盘加载到缓存 4个
write负责写入操作.缓存脏页刷新到磁盘中. 4个
log thread 日志缓存刷新到磁盘 1个
insert buffer thread :change buffer的内容写入到磁盘 1个
purge thread:
show variables like '%innodb_purge_thread%'
负责回收已经提交的undo页, 可以关闭
page cleaner thread:
show variables like '%innodb_page_cleaners%'
将脏页写入到磁盘.会调用write线程.释放redo log
innoDB数据文件:
文件存储结构:
Tablespace:
表空间存储多个ibd数据文件,存储表的记录和索引,一个文件包含多个段
Segment:
管理多个extent,分为数据段(leaf node segment)、索引段(Non-leaf node segment)、回滚段(rollback segment),一个表至少有两个segment 数据和索引,每多一个索引,就会多两个segment(索引和非索引)
Extent:
区的概念,固定包含64个连续的Page,大小为1M,当表空间不足,需要分配新的页资源时,会直接增加一个区,不会增加一个page,类似于地砖,你只能买一整块,不能买一个碎块
Page (最基本的单位):
页,存储多个row记录,大小为16k,包含数据page,undo page,系统page,事物page,大的blob对象page
具体结构:
header 头信息
body 具体的row
trailer 尾部信息
Row:
行,包含了该行的每个字段值,事物ID trx id, 滚动指针(roll pointer),不同session修改同一行数据的记录行为,形成一个链方便回滚.字段指针(field pionter)
文件存储格式:
查看的命令:
show table status; 在具体库中使用
select * from information_schema.innodb_sys_tables;
文件的格式是根据行格式来决定的,行格式为REDUNDANT、COMPACT对应Antelope,行格式为Dynamic和compressed对应Barracuda
innodb文件格式:Antelope和Barracuda
innodb行格式:Redundant、COMPACT、Dynamic、compressed
Redundant:
将变长列的前768b存在B树节点的索引记录中.其余在溢出页对与大于等于786b的也会转换为变长字段.方便溢出页存储
COMPACT:
与Redundant区别于 compact是紧凑型.但会增加CPU压力
Dynamic:
全都放到溢出页,索引记录只记录指向溢出页的指针.支持大索引引擎,最多为3072字节. 通过innodb_large_refix参数控制
Compressed:
针对Dynamic做高效压缩.其余功能一致.
修改row format:
alter table table_name row_format=format_name;
中途修改行格式不会影响之前的数据.
Undo Log:
undo就是撤销操作.回复到某个状态.
当事物开始之前,undo log会存储将要改变的记录和操作,当回滚时就可以利用undo log,事物提交前 undo log就会生成, 提交后并不会立即删除,而是把undo log放入删除列表中,等待 后台线程purge thread的删除处理,Undo log 属于逻辑日志,记录变化的过程.比如新增操作, undo log将会记录一个 delete操作, 反之一样.
采用段的方式管理和记录,在innodb数据文件中包含一种rollback segment回滚段,里面包含1024个 rollback segment
show varables like '%innodb_undo%' 查看undo log 的信息,
作用:
实现事物的回滚.
多版本并发控制(MVCC)
Redo log:
Redo:重做.当数据库发生问题时,redo可以重新做一次之前的操作.数据修改之后的信息记录在redo log中.
rodo log的生成:事物提交是先将修改数据存入change buffer,这时生成redo log,当该数据进入脏页
rodo log的释放:刷入磁盘时,对应的该条redo log 才会释放, 新的修改事物来后 该条redo log将被覆盖写入
Redo解决的问题:
如果没有redo log的机制,那么每次更新都要执行IO去刷新磁盘,而磁盘数据的位置不是整齐的摆放,而是随机位置的,这样就会增加IO的时间降低了效率,而将更新的数据顺序放入redo log,redo log再去IO 刷新磁盘,在一定意义上就是顺序IO,提升效率.
Redo log写入机制:
顺序循环方式写入文件,把所有log文件写满了后,从头开始覆盖写入.
Redo log相关配置参数:
show variables like '%innodb_log%'
至少有一个group日志, 一个group可有多个.默认2个
buffer刷新到redo log文件的策略:
0:事物提交就会写入log buffer,后台线程每秒刷新到OS cache再到磁盘的log文件.
默认1:提交时直接写入到buffer和OS cache,同时异步刷新到log文件.
2:提交时直接写到buffer和OS cache,但不启动任务刷新到log文件,等后台进程一秒刷新到log文件.
show variables like '%Inoodb_flush_log_at_trx_commit%' 来查看当前的策略.
Bin log:
redo log 是innodb引擎的功能,bin log是数据库的日志.负责记录表结构变更和数据修改的二进制日志.
默认是关闭的,以事件形式记录
应用场景:
主从复制:主库开启bin log,传递给从库.从库根据bin log进行数据恢复来达到数据一致.
数据恢复:灾难恢复,删库删表的情况,可以通过bin log文件来恢复数据和表结构
命名:默认主机名_binlog-序列号格式 也可以指定名称,
文件模式:
ROW格式:记录每一行数据被修改的情况,在slave端对相同的数据进行修改.
可靠、清楚记录修改细节,完全实现主从复制.
批量操作会占用大量空间,尤其修改表结构,日志暴增.
STATMENT格式:记录每一条修改的SQL.简称SQL复制.
日志量较低,但是sql有变化值(last_insert_id()、now())的话,那么数据一致性就无法保证了.
MIXED格式:混合模式,两种模式混合使用,一般使用statment,一致性无法保证时使用row格式.根据sql语句决定使用哪种格式.
文件结构:
事件:query、row、xid等.
一个一个的事件组成了bin log文件.
事件的结构:
timestamp 开始时间
event type 事件类型
server_id 服务器的id
event size 事件长度
记录机制:
1:执行操作会触发event事件生成log event(事件出发机制)
2:将log event写入缓冲区,每个事物线程都有一个缓冲区.query有query的这样.)
每个event保存在binlog_cache_mngr数据结构中,在该结构中有两个缓冲区,一个是stmt_cache,用于存放不支持事务的信息;另一个是trx_cache,用于存放支持事务的信息。
3:事物提交阶段会产生log event写入到外部的binlog文件
不同事物以串行方式写入binlog文件,是时间连续性的,不会被插入
binlog的一些操作:
状态查看:
show variables like '%log_bin%'
-针对只读的属性,只能去修改配置文件.cnf和.ini文件
开启:
log_bin:ON
log_bin_basename=binlog文件名
binlog-format=记录格式 ROW
查看文件状态:
show master status 查看文件
show 查看当前写入的文件名
show binlog events 查看事件
查看binlog文件(全局):
mysql目录/data下:mysqlbinlog "binlog文件名" >"输出到的文件名称"
恢复数据:
按照事件位置号恢复:
mysqlbinlog --start--position=位置号 --stop--position=位置号 binlog文件名 | mysql -u 用户名 -p 密码(不写就没警告,敲回车再输入密码一样的)
按照时间节点恢复:
mysqlbinlog --start--datetime=时间节点 --stop--datetime=时间节点 binlog文件名 | mysql -u 用户名 -p 密码(不写就没警告,敲回车再输入密码一样的)
定期备份数据库数据:
可定期做增量备份和恢复,用这些命令备份到另一个库
删除binlog:
purge binary logs to 'binlog文件'
purge binary logs before '时间节点'
reset master 清空所有binlog文件
自动清理:
定时清理:
show variables like 'expire_logs_days' 默认0 可set groble expire_logs_days 来设置多少天清理一次
binlog与redo log的区别:
相同点:
都是用于恢复一些之前的操作,记录一些曾经修改的数据记录.
区别:
redolog是innodb引擎的,binlog是mysql数据库的二进制的文件,级别不一样
redolog是物理日志记录具体数据.binlog记录是逻辑日志,以事件为基础,记录一些操作过程.
redolog是循环写入,空间大小是固定,binlog是追加写入,写满一个文件写下一个.
redolog做为服务器异常宕机的情况下短期数据丢失的自动恢复.binlog做为主从复制和灾难恢复的.没有自动的崩溃恢复.需要手动操作.
MySQL的索引:
提升查询速度,影响where查询以及order by排序.
存储结构划分:B tree索引,hash索引、fulltext全文索引、R Tree索引(Btree的多维空间)
应用层次划分:普通索引、唯一索引、主键索引、复合索引
索引键值类型:主键索引、辅助索引(二级索引)
从数据存储和索引值逻辑关系划分:聚集索引(聚簇索引)、非聚集索引(非聚簇索引)
索引的分类:
普通索引:normal index:
create index <索引的名字> ON tablename(filed name)
alter table tablename add index [indexname](fieldname)
create table tablename(field... index[indexname])
show index from tablename 查看当前表的索引
drop index indexname from tablename 删除指定name索引,不写就全删
唯一索引:unique index
允许null
增加和普通索引一样, 就是index前多了个unique
主键索引:primary
not null + unique的组合索引. 表中只能有一个.
复合索引:
多个字段组成的索引,当查询时某几个字段需要组合查询时,可以将这几个的单索引合成为一个复合索引.
窄索引和宽索引:1-2列为窄索引,超过两列为宽索引.
全文索引:
在varchar或者textarea上建立
数据量小时可用like,但数据量大时就需要使用全文索引了
创建该索引多添加一个关键字 fulltext
使用:
select * from table where match(field) against('str');
索引建立条件:
innodb引擎使用全文索引时,建立索引的最小大小默认是3个字符,最大为84个字符,myisam为4-84.不满足的话都不会建立索引,所以无法查询出结果,通过 show variables like '%ft%' 可以查看 myisam和innodb的全文索引相关参数.
只能通过配置文件修改了.属性都是只读的
切词语法:
检索的字符中含有一些指定的切分符号,才会匹配成功查询出来,否则不会查询出来
匹配结果:
默认是精确匹配(等值匹配) 需要使用*,再改成 in boolean mode才会实现类似于like '%%'的查询结果
索引的原理:
用于快速查找的一种数据结构,但需要额外的空间和维护.
存储位置:
物理数据页存储,在数据文件中 innodb就是ibd文件.利用page存储.
可以加快检索的速度.但是会降低插入操作的速度,因为需要修改索引.
理论:
二分查找、hash查找、B+tree.
二分查找:
优点:等值查询、范围查询速度快
缺点:插入数据成本高.
原理:
定位left和right
除2计算 出中位数与目标值比大小,大了就把左指针的位置变为中位数的位置+1(排除中位左侧区间),小了就把右指针的位置变为中位数的位置-1(排除中位右侧区间)
hash查找:
将字段值做hash计算后存储hash值,当查询等值数据时直接使用hash值进行查询,适合高速的等值查询.但范围查询速度就不会很快了.
memory引擎原生带hash索引,innodb有自适应hash索引.
自适应hash索引:
会根据数据访问的频率和模式进行自动的创建索引.无法认为干预.
使用hash索引访问时,一次查找就能直接定位到数据,等值查询时性能高于B+tree.
show engine inndb status; 查看索引相关信息
释放自适应hash索引:
show variables like '%innodb_adaptive%'.
set innodb_adaptive_flushing =0 关闭自适应hash索引
B+tree查找:
普遍采用.在Btree结构上优化而来.
Btree的特性:
索引值和数据分布在树中.
每个节点可存放多个数据和索引值.
有序排列(左至右)
流程:
从根节点进行搜索,采用二分查找.没有找到继续深入查询子节点进行二分,找到了就完成. 一直找到指针为null或者为叶子节点了,那么查找完成没有找到数据.
B+tree的特性:
非叶子节点不存储数据,只存储索引值.
叶子节点存储所有的数据和索引值.
每个叶子节点指针连接,提高区间访问
流程:
与Btree一致.
与Btree对比,B+tree不需要遍历所有的数据,而且每个叶子节点之间有指针关联,查询效率更快.但在等值查询时,Btree的速度相对来说会优于B+tree,因为非叶子节点存储数据,查询时等值到根节点时,直接查找完成.再插入时,B+tree的IO操作将会更低.因为只有叶子节点存储数据.
聚簇索引和非聚簇索引、主键索引和辅助索引:
聚簇索引:
索引值和行记录存储在一起.
主键索引:
一种聚簇索引,按照主键顺序构架B+tree结构.叶子节点的数据就是整行记录.innodb的表必须要有聚簇索引.有主键了,那么就有了聚簇索引,如果没主键,那么第一个unique列作为聚簇索引.如果还没有,innodb会创建一个隐藏的row-id作为聚簇索引,表中只能有一个聚簇索引.
辅助索引(二级索引、普通索引):
一种聚簇索引,也是B+tree结构.叶子节点只存储了索引列和主键的信息.表中可以有多个.查询时如果通过该索引查询时,通过值获取到该值的主键索引,再通过主键索引来获取整条记录.
非聚簇索引:
索引和数据分开存储.
索引分析与优化:
explain命令:
用来测试某一条sql的执行性能. 里面显示了详细的sql执行时的一些相关信息,如使用到的索引、查询的条数.
重要参数解析:
select_type:查询类型:
simple简单,不包含子查询与合并 -常见
primary最外层查询
union合并查询或后续查询
depedent union后续查询使用到了外面的查询条件.依赖外面一层的条件
union result 合并查询的结果
subquery子查询语句
depedent subquery依赖外面查询结果的子查询.
type:存储引擎查询时采用的方式.是全表扫描还是部分扫描,从上到下效率不断增强,null最强.
all:全表扫描,性能最低
index:索引查询,基于索引查询,先扫索引再扫全表.
range:使用索引范围查询,用了 大于小于等号in等等.只扫描一个范围了
ref:使用非unique索引进行单值查询.单个结果就是ref,多个结果还是all
eq_ref:多表join查询,每个记录都只能匹配后面一行结果.
const:使用主键或者唯一索引做等值查询.
null:表示不用访问表.dual的查询.
possible_keys:查询能够使用到的索引,不一定真正使用到
key:实际使用到的索引.
rows:扫描的行数,表示你这个sql要查询到结果需要扫描多少行(估算值).比如要查询出N条数据,那么最快的查询rows就应该是接近于N或者微微大于N,要是查10条扫描10000行,那这个sql效率就很低了
key_len:表示查询使用了索引的字节数量,可判断组合索引长度的使用占比.
规则:
字符串类型:跟字符集有关,
latin1=1、
gbk=2、
utf8=4、
utf8mb4=4
char(n): n*字符集长度
varchar(n)n*字符集长度+2可变字节
数值类型:
tinyint:1
smallint:2
mediumint:3
int、float:4
bigint、double:8
时间类型:
date:3
timestamp:4
datetime:8
字段属性:
NULL属性=1 加1个长度
not null属性:0 就不加
Extra:
显示额外的信息,各种操作会在Extra提示相关信息,
Using where
查询需要索引回表查询? 需要索引之外的信息
Using index
通过了索引就够了(索引覆盖)
Using filesort
对结果需要额外的排序.数据量小的化是内存排序,大的话就在磁盘了.如果有这个情况出现就需要优化一下了
Using temprorary
查询使用了临时表,出现于去重、分组等操作.要尽量避免了
回表查询:
当辅助索引查询没有查询到数据或者数据不完整,那么就需要去innodb必须的聚簇索引里去查找数据,这就是回表数据.相当于扫描了两个索引.辅助索引没满足.性能低了这样.
覆盖索引:
只需要在一个索引树上就能获取到sql查询的所有数据,就叫覆盖索引.这是性能最好的.
最左前缀原则:
复合索引在使用时,按照索引列的左侧顺序查询时,索引才会生效, 左侧开始向后连贯增加索引列也是生效的,一直可增加到全部索引列 索引都是生效的.但是如果打破了这个规则,比如不是最左侧的索引列或者最右的索引列,而且查询的索引列不是左侧开始连贯的,那么索引就不会生效
举个例子:
一个符合索引(field1、field2、field3)
select 1 生效,select 1,2生效,select 1,2,3生效
select 2 不生效 select 3不生效 select 1,3不生效 select 2,3不生效
关于Like与索引的问题:
使用like时,索引会不会生效?
5.6前 like的索引不会生效. 5.6后,like条件会进行下沉到存储引擎进行过滤.这会利用更充分.但也是有条件的,当前like条件中后面有通配符的或者没有才会生效.前面有通配符就不会生效.
关于null值列与索引的问题:
列有null时,索引会不会生效?
可以生效.因为null属性是占用空间的,所以我感觉索引也能够过滤null属性
null比空串更占空间,索引尽量避免一下,需要空那就设默认''.
索引与排序的关系:
filesort:把结果拿出来,然后在缓存或者磁盘进行排序,效率低哦.
filesort的排序算法:
双路排序:两次磁盘扫描读取,第一次将排序字段读取出来,第二次读取其他字段数据
单读排序:从磁盘读取所有列数据,然后在内存里排序.
如果查询的数据量超出sort_buffer的空间,那么会导致多次磁盘IO并创建临时表.会增加查询负担,所以尽量不要使用select * 或者设置一下 sort_buffer_size
show variables like sort_buffer_size 查看buffer大小.
如果我们查询时extra表达出了using filesort,那么就需要优化一下使之成为using index
using index索引的话本身就是有序的,所以就不需要额外的排序,效率很高,如果where+order by 可以将条件和排序的字段建立组合索引.再配合最左原则.
有索引也不好使的条件:
排序多个字段,排序方向却不同.
范围条件 < > .
没遵循索引的最左原则.
排序的多个字段都是单独的索引.
使用了函数.
MySQL的查询优化:
慢查询的一些原因:
全表扫描
全索引扫描 一直扫到索引树最底层,再去拿全数据.
索引过滤性低,设置了索引条件查询时却没有过滤很多数据
频繁的回表查询
开启慢查询日志:
show variables like 'slow_query_log%' 查看慢查询的一些功能和参数
set global slow_qeury_log = ON 开日志功能
set global slow_qeury_log_file = 'file name' 指定慢日志文件
set gloabl log_queries_not_using_index = ON 是否记录查询没有使用到索引的sql
set long_qurey_time = 10 查询超过阈值被记录
查看慢查询日志命令:
慢查询的优化:
范围查询如果范围过大,那么使用索引查询也会很慢.,是否使用索引只是SQL的执行过程,并不直接与SQL查询的快慢有关系.要提升查询一个SQL的查询速度,不光要建立索引,还要考虑查询条件可否缩小范围.定位精确.这样才能降低速度.
虚拟列:
可以将一些like查询的固定字段进行创建虚拟列,配合索引后达到等值查询的效果来提升速度
MySQL的分页查询优化:
limit的问题:
偏移量固定,变化取出数:
查询量小时变化差距较小.大时开始增加时间
偏移量变化,固定取出数:(翻页的机制)
偏移量在增加时开始翻倍的增加时间,limit在执行时,会从第一条开始扫描,所以当偏移量越来越大,sql limit需要扫描的条数就越多.所以性能就开始大幅的下降.
针对性优化:
使用覆盖索引来配合limit 进行扫描位置的提前定位,来避免limit page,10中的page过大而导致扫描记录过多.简单来说,不要利用page的变化来进行翻页查询,而是利用索引和固定偏移位取出当前页的ID做为起始的偏移位,再进行limit的查询时就避免了当前页数前的记录扫描.
sql: select * from user limit 10000,100; 效率低下
优化sql:select * from user where id>=(select id from user limit 10000,1) limit 100
查询上一个SQL的监控命令:profiling 需要打开,打开后就可记录SQL的执行监控数据
MySQL事物和锁:
事务的ACID:
原子性(要么都执行,要么都不执行redo和undo的作用),
一致性(保持数据修改后都为一致),
隔离性(必须保证某一数据被一个用户访问),
持久性(数据被修改后就永久生效,被记录了,回档也是利用了记录,相当于新增了一条修改记录,持久性概念没有变)
事务的并发问题以及隔离级别:
重复提交:更新的数据被覆盖或回滚
脏读:读到了其他人修改了但是没提交的数据.并发常见,锁的主要应用区域,互联网主要针对的区域,当避免了这个问题就会避免重复提交可幻读问题.乐观锁、悲观锁的主要针对问题.
不可重复读:读取到了修改后数据,以至于读了一次后再读一次结果不一致.这个问题不是灾难性的.因为这个现象没有产生灾难,容错率较高.
幻读:读到了新增或者删除的数据.也是属于容错率较高的情况.针对新增来说,幻读也是一个特有功能,如:刷新朋友圈,哈哈哈哈哈.但删除是一个影响体验的功能,比如刷着商品菜单,突然少一个,但这都为效果问题,一旦上升到数据库问题,那么将引起程序问题.所以用逻辑删除来避免数据库的物理删除,可降低这类问题风险.
事物的处理方式:
排队:按顺序一个个执行.
排他锁:可以实现并发,但是相同数据修改时,谁先加锁谁独占,其他都等着.这个场景适应一些修改个人资料,修改一些独占的信息.如用户、我的博客等.
读写锁:
读-读、写-写、读-写、写-读.四种场景并行处理,对并发处理进行细化,区别并发的操作来智能加锁.这样可以提高并发读的速度.但无法提高带有写的操作.
MVCC 多版本控制:
copy on write ,写入时先复制一份供其他事务来读.多余的版本在系统进程会定时清理释放undo空间.
生成机制:
事务操作时Undo日志会记录操作的事务号和修改数据状态.这样就可以通过undo日志进行更新前的查询,或者回滚数据等操作.
读操作:
快照读 不用加锁,但会读到历史版本、当前读:永远读最新的.但会加锁.
实现原理:
隐含ID 跟oracle的row id应该相同.
事务ID 该次事务操作的ID号.
回滚指针 更新回滚操作的标记点.来保证回滚的正确操作
流程1:更新时先创建redo log进行准备
流程2:更新数据
流程3:undo记录事务ID 状态,指针链接上一个版本的数据.
事物隔离级别:
隔离级别是SQL92标准,对并发事务的一种解决方案.是锁和MVCC的具体实现(封装)的体现
锁是处理并发的基础,对并发的事务进行控制.
可重复读隔离级别可能会发生幻读.当session1查询,session2新增或删除,seesion1再次查询是可以避免幻读现象,但session执行插入操作后,幻读现象将会出现.
事务操作流程:
开启事务 begin;
执行sql操作;
提交事务 commit
更改事务隔离级别:
show variables like 'tx_isolation' 或者 select @@tx_isolation
set [global] tx_isolation = 'read-uncommitted' 读未提交
set [global] tx_isolation = 'read-committed' 读已提交 oracle和sql server 的默认级别
set [global] tx_isolation = 'repeatable-read' 可重复读 默认级别
set [global] tx_isolation = 'serializable' 串行化
mysql锁:
表锁:安全高,并发最低
行锁:并发最好
原理:innodb是锁住索引.
record lock 记录锁
gap lock 间隙锁. 是一种范围锁
netx-key lock 上面两个锁的组合.锁数据也锁范围.
RR隔离级别:首先用NK锁,如果索引为主键和唯一.那么降级变为记录锁.
场景:
普通的select不锁.
select ... lock in share mode 共享锁添加 nk锁算法处理.有主键唯一索引,进行降级
select ... for update 追加排他锁 nk算法或降级处理(加锁基本操作)
update 也是排他锁 nk算法或降级处理
delete 同上
insert 同上 排他锁
锁定原理:
加锁:
主键索引直接给主键加锁
唯一索引加锁先给索引加锁,同时也给主键索引加锁
非唯一索引先锁索引,再锁间隙(GAP)锁和周边数据,最后锁周边主键
无索引的话会导致全表加锁和全间隙加锁.(所以一定要注意索引的使用,避免加锁的问题)
页锁:锁定一部分数据关联的数据.并发性能居中
读锁:S锁,共享锁,针对同时读取数据时多session不受影响.
写锁:X锁,排他锁,一个session写入没完成时,其他写入和读取都会被阻拦/
IS锁、IX锁:意向读锁和意向写锁.针对表锁. S和X是行级锁,读取和写入时先向表加上IS和IX锁,然后再会对具体行进行S和X锁
S锁可以被追加S锁,X锁不能被被追加X锁,连S锁都不能追加
乐观锁:大家都可以操作,直到更新时进行比对操作,冲突了进行报错.一定几率才会出现,但是能提高并发
不使用数据库和引擎的锁,通过我们逻辑控制,利用版本控制字段来解决冲突,冲突了的session不会影响到数据库,不会造成锁住的等待机制.而是直接返回失败.
悲观锁:
S锁和X锁都属于悲观锁 锁主数据不允许访问,就很悲观.
表锁:
手动给表加锁:lock table tablename read|write
查看表锁 show open tables;
删除表锁 unlock tables;
行锁:
共享锁:就只能读,可追加锁.
加锁select ... lock in share mode;
X锁写锁: 连读没法读了,也不能被追加
innodb引擎默认会将更新操作加上for update 排他锁
加锁select ... for update;
死锁:大部分死锁就是两个session在互相等待对方释放锁
表级死锁:
A先操作表1再操作表2.B先操作表2再操作表1. 双方都在等待对方释放锁.就造成了死锁. 这是属于逻辑设计问题.
要么都锁,别先锁表1再锁表2,要么就都别锁, 更改逻辑
行级死锁:
1.查了一个没索引的字段导致全表锁死.多个用户都这么执行,那么很容易就死锁了.别关联太多表查询,必要时可以拆开逐步查询,索引要建立完善但不是越多越好.
2.A操作行1再操作行2,B先操作表2再操作表1.也死锁了,这种死锁处理跟表级死锁一样.
共享锁转成了排他锁:
A加了S锁,紧接着换了个X锁.B想更新加X锁,结果A的S锁还在,B加不上X锁,A也因为没执行完等着加X锁, 导致了死锁.
如何排查死锁:
show engine innodb status 其中会报告死锁信息.
show status lik 'innodb_row_lock%'
MySQL集群架构:
大型互联网单库已经不能支撑住了,库要是崩了那将是毁灭性的.
当下环境高可用性是主要需求,在高可用性下维持数据一致和容错.也是数据库的分布式思想.
高可用的方法就是冗余,疯狂的剩余.
可用性的架构模式:
主从模式:高速读取,但写入需要自行优化
双主模式:互为主从.双主双写和双主单写. 双主单写更可控,较为安全.推荐使用.
拓展性的扩容:
加从库:主库性能便会降低,因为要推送binlog给从库同步.但是只能作为临时应急,如果持续性饱和,那么就需要设计新的结构了.
分库分表:分为垂直拆分和水平拆分. 垂直缓解部分压力,水平可以无限扩展.
一致性处理方式:
不要使用从库.但这又导致读能力低下了
路由层来控制,在同步的时间内,先使用主库,同步完成再可访问从库.
架构模式-主从模式:
高可读,一个主节点库,同步到其他的库中,采用异步复制.
实现原理:
主库收到插入操作,将操作写入binlog,从库去读取binlog并接收,然后写中继log:relay log,从库再从relay log进行回放来实现修改数据的效果.
用三个进程做工作1.binlogDump thread、2.IO thread、3.SQL thread
1:负责推送binlog给从库
2:负责将binlog 写入到relay log
3:负责将relay log恢复到库中.
问题:
会有延迟问题; 主库崩溃,从库没有复制完成,数据丢失了就.
半同步:
从库提交事务ACK主表也提交.5.5
增强版同步:5.7
从库收到binlog的日志就ack主库,主库与从库提交.
主从复制-并行复制:
将从库的两个线程进行多线程执行.其实只有sql thread多线程才有意义,io thread没啥太大作用,因为这个性能是主库发送时间和速度决定的.5.6、5.7、8.0都是并行复制.提升性能.
5.6的复制对于单从库的优势就发挥不出来了,可能会导致性能变低.执行顺序也会导致问题的存在.
5.7进行升级,组提交的概念.
show variables like slave-parallel-type
将binlog日志中不冲突的操作划为一组,然后并行执行.每组6个,指定的吗?
8.0的并行复制:
采用write-set并行复制,记录了事务修改的ID的HASH值,新来的提交日志需要和已经提交的ID hash进行比对.来判断是否冲突.这就精细化到了行级数据,达到了高并行.
复制模式:
commit_order 组提交
writeset:写集合机制
write session 比写集合多了一个约束,last_committer按先后顺序递增.
并行复制的监控:
show variables like 'replication%' 查看一些复制的参数
主从模式的操作方法:
主库
my.cnf配置文件配置:
binlog功能开启:log_bin=logName
设置server id:server-id=1
sync-binlog=1 每次同步进行写入磁盘.
binlog-ignore-db=忽略哪些数据库不同步
binlog-do-db=同步哪些数据库.
从库需要连接主库
授权:
grant replication slave on *.* to 'root'@'%' identified by root(8.0.x的版本不加密码)
grant all privileges on *.* to 'root'@'%' identified by 'root'
show master status;查看主库状态
从库:
my.cnf配置:
server-id=2 server id设置
relay_log=logName 中继日志名称设置
read_only=1 只读模式
初始化:
show slave status
change master to master_host='0.0.0.0',master_port=3306,master_user='username',master_password='password',master_log_file='binlogName',master_log_pos=postion
start slave
主从复制半同步复制:
需要安装插件:semi rpl_semi_sync_master (主从都需要安装,从库就把master改为slave)
select @@have_dynamic_loading;是否可以动态加载插件
show plugins 查看当前已有插件
install plugin pluginName soname 'semisync_[master/salve].so'(固定的) 安装插件
设置参数:
rpl_semi_sync_master_enabled = 1 开启自动半同步复制
rpl_semi_sync_master_timeout = 10000 设置超时时间
如何查看半同步复制是否成功:
主库:
查看下日志mysqld.log
主从复制并行复制:
主库:
show variables like '%binlog_group%' 查看事务组参数.
组同步参数设置. 设置延迟、设置每组事务数量
从库:
show variables like '%slave%' 查看从库中的组同步参数
设置同步slave_parallel_type 改为 logical_clock
设置并行线程数slave_parallel_workers 不要太大 最高设8就行
show variables like '%relay_log%' 查看中继日志参数
设置relay_log_recovery = 1; 需要改my.cnf
设置master_info_repository=table
设置relay_log_info_repository=table
查看并行复制信息:
切换到performance_schema库
select * from replication_applier_status_by_worker;
主从复制读写分离:
主库只负责写,从库只负责读,主从实现复制.
避免了死锁的风险,提高读的效率.
主库不建索引.负责读的从库建立索引,这样可提高写入速度.
面临的问题:
主从同步延迟的一些方案:
写后立刻读.一段时间内查询还是用主库,之后同步了再查询从库
二次查询.先去从库查询,从库没有的话再去主库查询.并没有实际减轻了主库压力.需要程序模块来控制查询频率
根据业务特殊处理:根据需求来决定哪些查询要求实时更新.哪些可以等待从库同步完成后查询成功.
具体的情况,需要按照项目的实际需求来灵活应用
主从分配机制的方案:
基于程序和配置进行分配,根据需求来切换数据源,比较常用.但可维护性不佳.
基于服务器端代理:
数据源只访问一个,这个数据源实际是个代理.他来选择读写的服务器.虽然增加硬件成本,但可维护性好.
代理中间件:
mysql proxy:服务端代理.
中间件的安装:
1.解压tar.gz
2.创建mysql-proxy.cnf配置文件
user=root 当前运行中间件的帐号
admin-username=root 主从用的帐号
admin-password=password
proxy-address=代理的地址:4040
proxy-backend-addresses=主库的地址们:端口
proxy-read-only-backend-addresses=从库的地址们:端口
proxy-lua-script=rw-splitting.lua的path
log-file=设置日志
log-level=日志级别
daemon=true 是否守护进程 true守护进程
keeplive=true 是否崩溃重启
3.给文件指定权限 chmod 777 mysql-proxy.cnf
4.修改rw-splitting.lua
min_idle_connections=最小读写分离启动连接数,改为1可查看效果,实际应用根据并发量设置.
5.启动 ./mysql-proxy defaults-file=./mysql-proxy.cnf
6.打开火墙对应端口
中间件的使用:
命令行的图形化针对8.0会有问题,所以可以直接使用图形化工具,命令行会找不到表...
使用可视化工具创建代理的连接
在代理中insert 查看是否设置生效. 暂时先stop slave 来停止复制
在代理中select 查看时看是否是读库查询. 断开了复制,不会同步,那么主从就有数据差.一定能看出来效果.
myCat: 基于阿里cobar开发
shardingSphere:开源分布式中间件,包含sharding-jdbc、sharding-proxy.应用级分配就是用sharding-jdbc
atlas:360开发的中间件.基于mysql proxy0.8的版本升级
amoeba:早期的代理中间件.不支持事务、分库分表
主从模式-双主模式:
主从复制中,一主多从的情况下,如果写入需求很大,那么单主就会形成性能瓶颈,而且如果主库崩溃,那么应用将不可用.所以需要双主模式来保证可用性.
多主模式其中的两台主库其实互为从库.但根据server id不会引起无限循环.
双主双写:
会出现的问题:
ID冲突.当1号主写入后没有同步到2号主库,2号主库又接到写入请求,这就会导致两个库写入用了同一个ID(针对自动递增.).但是也可以避免.但对后期扩展支持不友好.
更新丢失:同一条记录在2个主库同时更新,就会导致更新冲突而丢失一条记录.控制较为复杂.
双主单写(推荐,较为安全):
不会轮询使用双主(应用来控制).另一个主库是做为备用库做好准备的.当其中一个主库故障,自动切换到另一台主库.同时从库也要跟过去.stop再start?
双主的配置方法:
1号主库:
my.cnf配置:
relay_log=log_name 开启中继日志功能.
log_slave_updates=1 更新是否写入binlog
auto_increment_offset=1 双主单写不需要配置了就 双写的ID起始位置
auto_increment_increment=2 生成ID间隔
做主库关联2号库(1号对于2号就是2号的从库)
change master to master_host='',master_port=3306.....
2号主库:
my.cnf配置:
配置同1号主库
做主库关联1号库(2号对于1号就是1号的从库)
change master to master_host='',master_port=3306.....
binlog的时间点容易导致数据库结构不同.注意避免,尽量双库从0开始搞.
MMM架构:
一个三方软件,master-master replication manager for mysql
可以实现1号崩溃自动切换到2号主库.
一个主库为写入,另一个备用主库设为读.双主互相复制.从库一直跟着写入的主库.写入主库崩溃,读取主库转换为写入,从库更换复制主库.
MHA架构:
基于主从模式,主库故障后,将从库快速切换为主库.可以管理多个集群.
由manager和node组成.
切换数据库流程:
保存主库binlog.
找寻最新的slave
用最新的slave 的relaylog修复其他从库
将保存下来的binlog恢复到最新的从库
将最新的从库升为主库
其他从库指向新的主库.
MHA配置方法:
更改主库my.cnf:
relay-log=mysql-relay-bin //开启中继日志
skip_name_resolve 关闭名称解析
主从复制-主从切换策略:
主备延迟问题.
show slave status中 seconds_behind_master表示备库同步的延迟时间.
网络问题、备库性能差、单个机器当多个主库的从库都会影响可用性、分工问题、大事务操作
可靠性优先:
判断从库的SBM延迟值,小于阈值开始下一步操作
主库设为只读(这个时间节点将不可写入,影响可用性)
等待B库的SBM延迟降为0
B库改为读写状态.
应用的写入请求调转到B库上.B库成为主库.
可用性优先:
A库写入后binlog发送给从库时,从库被快速切换为主库,并收到了写入请求.这时binlog还没有同步.这就导致主键被占用.升为主库的从库同步给原库时就会出现数据冲突.
分库分表架构:
数据量在疯狂的堆叠.主从复制的模式就无法解决.
拆分方案:单分库、单分表、分库分表
拆分模式:
垂直拆分:表数量庞大.拆成多个库存储
应用层来说.只是切换数据源了而已
垂直分表:将一个大表拆分成多个小表.主从表的思想.
优点:业务清晰.规则明确;可扩展好;减少IO次数;提高查询速度,最大化利用cahce;冷热分离
缺点:主键冗余,要做关联查询.(现在开发我已尽量减少表连接查询sql,转用程序级循环查询);单表数据量过大问题没有解决.
水平拆分:单表数据量多大.分成多个表存储
优点:拆规则设计好.表连接就可关联起来..不存在单库大数据.拆分后表结构相同.不需要改动应用过多.提高系统稳定性和负载能力
缺点:拆分规则复杂;会出现跨库查询;一致性事务较难;扩容和维护量大.
业务上,更关注垂直拆分.进行细化. 技术上,使更注重水平拆分.提高应用本身性能.
分布式ID主键生成策略:
UUID:耗费空间,对索引树影响较大,因为UUID无序.
COMB UUID的变种:有序的UUID,解决了对索引的影响
SNOWFLAKE:雪花算法.LONG型占用空间小,有序.但强依赖系统时钟.大厂都单独封装.
专门的数据库ID表:在这表里生成ID,再插入到业务表中,风险较高,性能无法保障
Redis生成ID:用redis生成全局ID,集群redis就需要设置好间隔.扩展性不太好
分片策略:
sharding,把一个整体数据库打散,进行分散存储.
将整体数据按一定的规则进行拆分存储的流程思想就是分片.而分库分表是结果.
根据数据中的某个字段作为分片键进行分片.
基于范围分片:
根据分片键的指定范围进行分片.
优点:新数据落在新节点上.扩容不需要迁移数据.
缺点:数据分布不是很均匀.导致查询权重失衡.新节点压力会过大.造成洪峰.
hash、%分片.
对于数字型key直接%运算进行分片,非数字型进行hash运算后%运算分片.
优点:实现简单.数据分布较为平均.,不会存在权重问题.
缺点:需要将已有数据进行重新分配迁移.增加节点就需要重新计算,
一致性hash分片:
为了避免扩容时导致的迁移问题.只需要迁移少部分数据.不需要对整体数据进行迁移调整.只会影响hash环中两个节点之间的数据
扩容方案:
首要面临问题:数据迁移问题、分片规则更改、数据同步、时间点、一致性
停机扩容方案:
服务下线,进行扩容操作.进行数据导出,增加节点,数据导出,分片,导入.
适用于小型项目,管理系统类项目.
平滑扩容:
保持可用性的情况下,进行无感扩容.只能扩容到原有数量的2倍,将扩容的节点与原有节点进行双主同步,保持可用性,并开启双写模式,然后关闭双主同步模式.然后根据分片规则对每个库的数据进行删除.
不需要迁移数据,服务高可用,对完成没有限时,可调试.不影响线上服务.降低已有库的性能.
缺点:配置较为复杂,双主同步、开启双主双写,检测数据同步性问题.迭代成本较高
始用高可用的服务.大型互联网