大表批量删除问题
删除一条记录,首先锁住这条记录,数据原有的被废弃,记录头发生变化,主要是打上了删除标记。也就是原有的数据 deleted_flag 变成 1,代表数据被删除。但是数据没有被清空,在新一行数据大小小于这一行的时候,可能会占用这一行。这样其实就是存储碎片。
之后,相关数据的索引需要更新,清除这些数据。并且,会产生对应的 binlog 与 redolog 日志。 如果 delete 的数据是大量的数据,则会:
- 如果不加 limit 则会由于需要更新大量数据,从而索引失效变成全扫描导致锁表,同时由于修改大量的索引,产生大量的日志,导致这个更新会有很长时间,锁表锁很长时间,期间这个表无法处理线上业务。
- 由于产生了大量 binlog 导致主从同步压力变大
- 由于标记删除产生了大量的存储碎片。由于 MySQL 是按页加载数据,这些存储碎片不仅大量增加了随机读取的次数,并且让页命中率降低,导致页交换增多。
- 由于产生了大量日志,我们可以看到这张表的占用空间大大增高。
大表批量删除对查询的影响
- 当新的会话执行SQL时,如果扫描区间内有大量被标记删除的记录,会导致SQL执行效率低。例如where c1 = 1,有10晚match的记录时,其中扫描方向90%的记录都被标记为已删除,但还没有purge就会效率低(已经提交的事务只有在RR隔离级别下会出现这个情况)
大数据量表如何新增字段
- 基础方法:几十万数据一般可以直接添加
- 临时表:复制临时表,加上新增字段,然后拷贝过去
大数据量limit问题
limit页数特别大的时候回影响性能,可以先选好id范围,大于某个id再用limit
快速批量插入
- buffer_size 空间 和 max_allowed_packet语句运行长度设最大
- insert into table (v1,v2,v3) values (a,b,c),(a,b,c),(a,b,c)
使用mybatis批量插入的话,循环插入最不可取,可以使用原生拼接,插入效率最高,但是需要调整和预估好SQL限制,不然容易程序报错
大表性能问题
- 建表字段小
- 索引(不走索引的查询会很慢)
- 归档数据、冷热分离
- 读写分离
- 分库分表
碎片化空间处理
- mysql check可以找出表空间中超过10M的最大的10个表
- 也可以通过data_free进行判断碎片化空间的大小
- alter table xxx force 可以对表空间进行整理(随机IO,比较耗时,也会阻塞表上正常的DML运行)
- 复制一个新表,拷贝过去
PGsql和Mysql的区别
PG的优势:
- PG的主从复制属于物理复制,相比mysql通过binlog的逻辑复制,数据的一致性更加可靠,复制性能更高,对主机性能影响也更小。
- 优化器的功能更加完善,支持索引的类型更多,复杂查询能力更强
- 功能集更出色
- PG主表采用堆表存放,比Mysql的索引组织表,支持更大的数据量
Mysql的优势:
- Mysql的优化器先对简答,但也更适合简单的查询操作,因为在并发高的项目里,对数据库的查询上很少会有复杂查询
- 存储引擎插件化,使其更灵活,应用场景更广泛
- 索引组织表,这种查询方式更适合主键匹配查询,有聚簇索引
分库分表
水平分表方案:时间维度分表、用户id一致性hash取模
sharding-sphere(sharding-jdbc)
是一个jar包,使用时需要修改代码
优点:
- 轻量,范围更容易界定,只是 JDBC 增强,不包括HA、事务以及数据库元数据管理
- 无运维成本,无需关注中间件本身的高可用
- 性能高,JDBC直连数据库,无需二次转发
- 可支持各种基于JDBC协议的数据库,如:MySQL,Oralce,SQLServer
缺点:
- 不够通用,仅支持某一种语言。
- 版本升级困难,如果中间件有问题,使用该中间件的所有服务都需要升级。
分布式全局唯一ID
雪花算法
使用一个64bit的long型数字作为全局唯一id。
- 1bit:0,无意义
- 41bit:时间戳
- 5bit:机房id
- 5bit:机器id
- 12bit:序号,某机房某机器上这一毫秒内同时生成的id的序号
UUID/GUID
规范定义了包括网卡MAC地址、时间戳、Namespace、随机数、时序等元素,UUID的复杂性保证了它的唯一,但是这个唯一性是有限的,只在特定范围内保证。
分片规则和策略
- 随机分片hash
- 连续分片
基因法
跨分片技术问题
跨分片的排序分页
跨分片的函数处理
跨分片join:(全局表、字段冗余来解决)
TDDL
mycat
在中间件层,是一个第三方应用,不需要改代码,所有的jdbc请求都要先交给mycat,再转发给真实的服务器。
- 优点:通用,改造少,多语言支持
- 缺点:需要二次转发,有性能损失,有运维成本
读写分离数据一致性问题
数据同步写入:主从同步改成同步方案,但会影响性能
读数据从主库读:直接改成从主库读
****缓存路由:写库的时候把key存到缓存中,存较短时间(经验值),读的时候先去缓存判断是否存在key,存在则去主库读,否则去从库读。
缓存存储:请求去存数据库的时候,同时缓存数据,后续业务先从缓存中拿,会有缓存和数据库一致问题