Mysql

字段选择

  1. 尽量选用INT,BIGINT,4字节8字节的消耗小于varchar。字符串选择VARCHAR增加拓展性。
  2. 时间应使用时间戳BIGINT存储,不使用DATETIME。
  3. 不使用BLOB字段,如有需要,应以主键为Key写入KV数据库。
  4. 不存储长文本进行查询,如有需要,考虑使用ES。

分表

应控制住表的行数,主要考虑垂直拆分和水平拆分。原则是:属性不同的表垂直拆,拆了如果还是大表,再按时间、UID前缀等进行拆分。

垂直拆分:按业务维度分离(用户表 vs 订单表)。水平拆分:Sharding策略(范围、哈希、时间)

  1. 无限递增的大表应配备清理机制。如聊天记录表。
  2. 多考虑使用日期进行分表,简单且有效。用户表考虑使用UID前缀。

索引和查询优化

索引在读多写少场景使用索引,能极大提高查询效率。索引文件的本质是B+树,我们可以从二叉树的原理分析查询语句性能。

  1. 应结合高频sql语句,选用查询频率高,且差异大的字段为索引。如:UID,创建时间。

    举例,这是一张订单表,忽略了分表细节。
create table t_order
(
order_id bigint unsigned not null primary key COMMENT '主键。公司订单号',
platform varchar(32) not null default '' COMMENT '平台名称',
channel varchar(32) not null default '' COMMENT '渠道',
price bigint not null default 0 COMMENT '价格',
payment integer not null default 0 COMMENT '支付类型',
third_party_order_id varchar(256) default null COMMENT '第三方订单号',
pay_channel varchar(256) not null default '' COMMENT '支付渠道',
game_uid varchar(256) not null default '' COMMENT '业务方UID',
product_id varchar(256) not null default '' COMMENT '商品PID',
order_status integer not null default 0 COMMENT '订单状态',
item_id varchar(256) not null default 0 COMMENT '道具id',
created_at bigint not null default 0 COMMENT '创建时间',
updated_at bigint not null default 0 COMMENT '更新时间',
deleted_at bigint default 0 COMMENT '删除时间',
KEY `idx_uid` (`game_uid`) USING BTREE,
KEY `idx_third_order_id` (`third_party_order_id`) USING BTREE
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'order';

常用sql语句为:

按订单号:order_id = ?

丢失订单号时,按按uid+第三方订单号:product_id = ? AND game_uid = ?  AND platform = ? AND order_status = ? 

检查该订单是否已经被核销过:third_party_order_id = ?

三条语句分别命中了三个索引。最常用的根据主键查询订单,以及命中game_uid和third_party_order_id。

  1. 语句应触发索引,避免锁表。也要注意避免索引失效,编写完成后应使用EXPLAIN检查sql语句。

    常见的索引失效场景:
  • 联合索引中,跳过1直接使用2,3号索引。
  • 使用左模糊查询:LIKE'%abc',会导致索引失效
  • 不要对索引列进行计算:WHERE YEAR(create_time) = 2023。应在程序中提前计算好2023年的范围。
  • 对字符串类索引要加单引号,避免自动类型转换导致索引失效。
  • 使用“OR”时,如果有任一条件不是索引,则索引失效。

    EXPLAIN可进行sql分析,重点关注type字段。
  • key:触发了哪个索引
  • rows:扫描行的数量。
  • type:ALL(全表扫描)→ index(只遍历索引树) → range(范围查询) → ref(非唯一索引) → eq_ref → const(唯一索引)
  • Extra:Using filesort(需优化)、Using index(覆盖索引)
  1. 如有字符串索引匹配需求,考虑使用ES或本地存储库。

一个性能优秀的本地存储,项目上用于对玩家昵称进行模糊搜索:github.com/blevesearch/bleve/v2

加缓存

当实在无法优化时,对于读多写少的表考虑使用缓存。介绍几种常见的场景:

  1. 内存缓存

    当数据实时性不重要时,将上一次读表的结果缓存,并设置一定时间后数据过期,能极大减少读表频率。
  2. 读Redis写Mysql

    是移动互联网刚兴起时非常流行的架构。写Mysql,通过中间件捕获binlog直接写kafka,服务只需消费kafka并写入Redis。

    性能介于直接使用mysql和使用Pika之间。老项目若mysql无法迁移可以选用,新项目可以考虑直接使用Pika存储。

Pika是一个性能优秀的KV持久化数据:https://github.com/OpenAtomFoundation/pikiwidb/wiki/pika-介绍

mysql观测

开启慢查询日志

SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1; -- 超过1秒的记录

查看当前sql

SHOW processlist;

查看索引使用统计

-- 查看未使用的索引
SELECT * FROM sys.schema_unused_indexes;

RocksDB系存储

KV系存储的核心是数据结构,结构选对了,性能就优化上来了。RocksDB只有KV一种数据结构,Pika对RocksDB的底层KV数据结构进行封装,所以上层结构就很显而易见了。

下面介绍Pika和Redis的数据结构:

string list hash zset set
Pika KV 分开存,记录首尾 分开存,使用统一前缀 分开存,利用RocksDB的按序扫描特性 分开存,依赖RocksDB的键唯一性实现去重
Redis 数字或字符串 压缩列表、双链表 压缩列表、散列表 跳表、散列表 整数集、哈希表

所以Pika更适合使用string、hash对proto进行序列化后存储,因为数据会落磁盘,成本比Redis更低。Pika单点支持20W QPS,性能比mysql更好。

list常用于消息队列建议使用kafka。set可用Redis进行去重,Pika会前缀匹配所有Block性能很差不要用。zset常用于排行榜使用Redis,Pika同样会扫描所有Block不要用。

RocksDB架构

RocksDB将数据分为多个block,多个数据块组合成一个SST文件。每个SST的被放置在其中一层。每次进行Compact,会使用LRU算法将不常用的SST落到更低的层级。

  1. 数据会先被写入到MemTable,这是一个跳表实现的内存结构。写满后转为只读状态,等待刷盘成SST文件。
  2. SST文件是磁盘上的不可变有序文件,由以下成员组成:
  • Data Blocks:实际存储,按Key进行排序
  • Index Block:记录每个Data Block的起始Key和偏移量。
  • Footer:元数据(索引、过滤器位置等)。
  1. Block是SST文件中的最小存储单元,由以下成员组成:
  • Key-Value Entries:有序键值对。
  • Restart Points:每隔若干Key记录一次绝对位置,加速二分查找。
  • Trailer:包含压缩类型和CRC校验码。

    Leveled Compaction

    将高层SST文件刷到低层的过程。还会合并旧文件以减少查询需要访问的文件数。

    查找

    通过Index Block定位目标Data Block,再从磁盘或缓存中加载Data Block,在Block中通过二分查找定位Key。

概述协作流程为:

Client->>MemTable: 写入数据(Put)

MemTable->>SST: MemTable写满后Flush为SST文件

SST->>Block: SST文件按Block存储数据

Client->>Block: 读取时通过Index定位Block

写放大

由于MemTable的数据会被刷到磁盘,SST文件会被刷到低层,所以会存在数据被写多次。

读放大

由于会分为多个SST文件,所以查询时可能会读多个SST文件。

空间放大

一个Key可能会存在于多个SST文件中。

过期时间

对RocksDB使用过期时间不是个好决定。因为SST中的数据是不能删除的,所以Pika只是通过字段标记其过期时间,过期后数据仍然会占用存储空间。对于临时数据,使用Redis是更好的选择。

mysql、PikaDB的使用方法和优化策略的更多相关文章

  1. MySQL中的SQL的常见优化策略

    MySQL中的SQL的常见优化策略 MySQL中的索引优化 MySQL中的索引简介 1 避免全表扫描对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索 ...

  2. Mysql 52条SQL语句性能优化策略汇总

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在where及order by涉及的列上建立索引. 2.应尽量避免在where子句中对字段进行null值判断,创建表时NULL是默认值,但大多数时候应 ...

  3. Java 程序优化:字符串操作、基本运算方法等优化策略(二)

    五.数据定义.运算逻辑优化 多使用局部变量 调用方法时传递的参数以及在调用中创建的临时变量都保存在栈 (Stack) 里面,读写速度较快. 其他变量,如静态变量.等,都在堆实例变量 (heap) 中创 ...

  4. [转]mysql大表更新sql的优化策略

    看了该文章之后,很受启发,mysql在update时,一般也是先select.但注意,在Read Committed隔离级别下,如果没有使用索引,并不会锁住整个表, 还是只锁住满足查询条件的记录而已. ...

  5. mysql大表更新sql的优化策略(转)

    看了该文章之后,很受启发,mysql在update时,一般也是先select.但注意,在Read Committed隔离级别下,如果没有使用索引,并不会锁住整个表, 还是只锁住满足查询条件的记录而已. ...

  6. PHP中的数据库一、MySQL优化策略综述

    前些天看到一篇文章说到PHP的瓶颈很多情况下不在PHP自身,而在于数据库.我们都知道,PHP开发中,数据的增删改查是核心.为了提升PHP的运行效率,程序员不光需要写出逻辑清晰,效率很高的代码,还要能对 ...

  7. mysql 30大优化策略

    mysql 30大优化策略 1.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描. 2.对查询进行优化,应尽量避免全表扫描,首先应考虑在 wher ...

  8. Mysql千万级大表优化策略

    1.优化sql以及索引 1.1优化sql 1.有索引但未被用到的情况(不建议) (1)避免like的参数以通配符开头时 尽量避免Like的参数以通配符开头,否则数据库引擎会放弃使用索引而进行全表扫描. ...

  9. mysql索引之四:复合索引之最左前缀原理,索引选择性,索引优化策略之前缀索引

    高效使用索引的首要条件是知道什么样的查询会使用到索引,这个问题和B+Tree中的“最左前缀原理”有关,下面通过例子说明最左前缀原理. 一.最左前缀索引 这里先说一下联合索引的概念.MySQL中的索引可 ...

  10. mysql 优化策略

    from:https://dbaplus.cn/news-155-1531-1.html MySQL逻辑架构 如果能在头脑中构建一幅MySQL各组件之间如何协同工作的架构图,有助于深入理解MySQL服 ...

随机推荐

  1. Netty实战入门教程

    概述 Netty 是一个异步的.基于事件驱动的网络应用框架,用于快速开发可维护.高性能的网络服务器和客户端 Netty 在 Java 网络应用框架中的地位就好比:Spring 框架在 JavaEE 开 ...

  2. 云主机AI服务的性能测试和优化

    本文分享自天翼云开发者社区<云主机AI服务的性能测试和优化>,作者:无敌暴龙兽在云计算的时代,越来越多的人选择将AI模型部署在云主机上,以便利用云服务提供商的弹性和可扩展性.然而,仅仅将A ...

  3. Java代码覆盖率工具之Jacoco

    Java代码覆盖率工具之Jacoco JaCoCo(Java Code Coverage)是一款面向Java语言的开源代码覆盖率工具,以其小型化和轻量化著称.它能够提供代码在测试过程中的覆盖率信息,帮 ...

  4. CF1326G 题解

    题意: 蛛网树是一颗平面树,满足点是该树的凸包的顶点上等价于其是叶子. 给定一个平面树,求有多少种对点集的划分,使得每个划分出来的集合都是蛛网树. Solution 考虑树形 dp.设 \(f_u\) ...

  5. Luogu P1613 跑路 题解 [ 蓝 ] [ 倍增 ] [ Floyd 最短路 ] [ 状压 dp ]

    跑路:绝佳倍增好题,思路是化 \(2^k\) 为 \(1\) ,倍增起预处理作用. 最近不知道是撞了什么运,前一脚看的是绿题,写完之后交一发,发现直接被 lxl 升蓝了,血赚. 思路:Floyd 首先 ...

  6. [JOI 2020 Final] 火事 题解

    给一篇题解.(下面这张图是从 luogu 上粘贴的,因为不太会画图) 其中纵坐标为 \(t\),横坐标为 \(a_i\). 发现同颜色块只有平行四边形和直角梯形(等腰直角三角形)两种情况. 可以将直角 ...

  7. 【COM3D2Mod 制作教程(6)】实战!制作身体部分(下)

    [COM3D2Mod 制作教程(6)]实战!制作身体部分(下) 有了上一章制作帽子的经验,此时做头发很多就不必再重复赘述了,但如果用完全一样的流程和方法,把头发做好后直接装扮就会导致游戏报错,这就是我 ...

  8. C#之 Dictionary 详解

    基本概念 Dictionary<TKey, TValue>是C#中用于存储键值对集合的泛型类,属于System.Collections.Generic命名空间.它允许使用键(Key)来访问 ...

  9. 玩three.js的一点心得

    契机: 3-4月份,有机会再次学了一遍高数,然后再一次从二,三重积分的坑里爬来爬去,其中有个直观的问题一直困扰着我就是一个函数在空间坐标系上的图像,所以当时就打算学完这些之后,自己在5月份的时候用th ...

  10. sourcetree 重新设置git账号密码

    设置提交git账号邮箱 到项目根目录,执行 vi ~/.gitconfig ,直接编辑修改即可 重新设置git登陆账号密码 打开 sourcetree 的偏好设置,选择高级,然后移除即可