mysql索引字段设计

news/2025/2/11 22:25:20/

表字段数量与row大小限制可以参考官方文档
https://dev.mysql.com/doc/refman/8.0/en/column-count-limit.html#column-count-limits

复合索引

参考:https://dev.mysql.com/doc/refman/8.0/en/innodb-limits.html

数量限制

一个复合索引最多可以包含16个列:https://dev.mysql.com/doc/refman/8.0/en/multiple-column-indexes.html
官方对组合索引给出了一个比较好的可行方案:可以引入基于来自其他列的信息进行“散列”的列,方法如下:

SELECT * FROM tbl_nameWHERE hash_col=MD5(CONCAT(val1,val2))AND col1=val1 AND col2=val2;

大小限制

innodb索引大小限制

  • 对于使用DYNAMIC(5.7.9开始默认为该格式)或COMPRESSED行格式的InnoDB表,索引key前缀长度限制为3072字节。
  • 对于使用REDUNDANT或COMPACT行格式的InnoDB表,索引key前缀长度限制为767字节。例如,在TEXT或VARCHAR类型字段上列前缀索引超过191字符,可能会达到这个限制,假设一个utf8mb4字符集,每个字符最多4个字节。
  • 试图使用超过限制的索引键前缀长度将返回错误。
  • 如果你在创建mysql实例时通过innodb_page_size参数配置,减小InnoDB的page页大小至8KB或4KB,索引的最大长度也会基于16KB页大小3072字节的限制,按比例降低。也就是说,当页大小是8KB时最大索引键长度是1536字节,页大小是4KB时最大长度为768字节。该限制适用在索引键前缀,也同样适用在full-column索引键

为什么是3072?
16KB page size

  1. BTree结构叶子结点至少两个Node(不然就退化成列表了),16/2=8KB
  2. 二级索引一定包含一个主键索引key,8/2=4KB

预留空间后<4KB,取整=3*1024=3072

row format

mysql> SHOW TABLE STATUS FROM test LIKE 't%' \G;
*************************** 1. row ***************************Name: t1Engine: InnoDBVersion: 10Row_format: DynamicRows: 0Avg_row_length: 0Data_length: 16384
Max_data_length: 0Index_length: 0Data_free: 0Auto_increment: NULLCreate_time: 2021-02-18 12:18:28Update_time: NULLCheck_time: NULLCollation: utf8mb4_0900_ai_ciChecksum: NULLCreate_options: Comment:

计算索引长度

  1. 非NOT NULL字段:占用1个字节。
  2. 定长字段:tinyint占1个字节、int占4个字节、bitint占8个字节、date占3个字节、datetime占5个字节,char(n)占n个字符。
  3. 变长字段:varchar(n)占n个字符+2个字节。

其他类型大家可以通过本地创建测试表测试索引验证字段类型占用字节数
常见字符集一个字符占用字节数

  1. latin1编码:每个字符占用一个字节
  2. gbk/gb2312编码:每个字符占用两个字节
  3. utf8编码:每个字符占用三个字节
  4. utf8mb4编码:每个字符占用四个字节

案例

CREATE TABLE `test` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Primary key',`msg_id` varchar(64) NOT NULL COMMENT 'msg unique id',`send_to_id` varchar(128) DEFAULT '' COMMENT 'to user',`error_code` varchar(64) DEFAULT '' COMMENT 'errorCode',`db_create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Create time',PRIMARY KEY (`id`),KEY `idx_send_to_id` (`send_to_id`,`error_code`,`msg_id`,`db_create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

查看执行计划

desc select msg_id,error_code 
from test 
where send_to_id='1' 
and error_code in ('a') 
and msg_id='1' 
and db_create_time='2022-12-12'

截屏2022-12-15 14.48.37.png

  1. varchar3个字段共占用(64+64+128)4=1024+(23)=1030
  2. datetime(3)占用5+2=7
  3. 两个非NOT NULL字段1+1=2

索引占用1030+7+2=1039字节

索引设计

群发消息场景

  1. 一个批次消息推送对应600W+用户的消息触达
  2. 异步推送时消息失败需要重试,重试需要幂等处理
  3. 产品需要查看一个批次消息的推送的详情,因此分库规则使用了msgId(群发消息的批次概念)

幂等规则:msg_id+send_to

伪代码:select msg_id,error_code from table where msg_id=‘a’ and send_to=‘1’。
为什么需要error_code,因为有些类型的失败消息不允许重试,比如:用户已注销账户或者用户已退订等类型

群发消息场景下,600W+条消息都是同一个批次,也就是msg_id相同,send_to均不相同,error_code(大部分消息发送成功,errorCode为空字符)

索引覆盖

不需要二次回表,直接索引覆盖索引,字段顺序选择如下:

  1. idx_send_to(msg_id,send_to,error_code)
  2. idx_send_to(error_code,send_to,msg_id)
  3. idx_send_to(send_to,error_code,msg_id)
  4. idx_send_to(send_to,msg_id,error_code)

假设:表中每个字段的distinct值,send_to=600W,error_code=20,msg_id=50W。表总数据量为:600W2050W=600000W

选择性
选择性=不重复的索引值数量/表记录总数量
msgId选择性:50W/600000W=0.000083
send_to选择性:600W/600000W=0.001
error_code选择性:20/600000W=0.0000000033
理想情况下索引性能由高到低依次为:索引4-》索引3-〉索引2-》索引1
但是如果send_to与msg_id:1对1或者1对二,二send_to与error_code:1对20,那么索引3就是最佳选择,例如下面的案例,mysql自动选择走索引3,而不是索引4
截屏2022-12-15 23.00.42.png

截屏2022-12-15 23.02.21.png

截屏2022-12-15 23.03.30.png

总结

基于索引选择性创建联合索引,字段设计可以根据实际业务场景来评估
例如:字段1(基数=10W),字段2(基数=10W),字段3(基数=20)
虽然字段1,2独立的选择性更高,但是如果字段1与字段2基本1:1,而字段1与字段3基本1:5。那么字段1+字段3无疑是更佳的选择


http://www.ppmy.cn/news/12435.html

相关文章

【JavaSE】Java反射机制详解

【JavaSE】Java反射机制详解 文章目录【JavaSE】Java反射机制详解一&#xff1a;反射简介&#xff1f;二&#xff1a;反射的应用场景三&#xff1a;反射实战1&#xff1a;获取 Class 对象2&#xff1a;获取构造方法3&#xff1a;获取字段4&#xff1a;获取方法5&#xff1a; 反…

我们怎样才能过好这一生?

文章目录1. 日拱一卒&#xff0c;功不唐捐1.1 适当的时候给自己一个奖励1.2 一个人可能走的更快&#xff0c;但一群人才能走的更远1.3 通过一些事情去逼自己一把1.4 从真理中去感悟1.5 当你面临绝路时2. 梦想的意义不在于实现3. 孤独4. 烦恼5. 别总说来日方长6. 忍和韧性7. 事情…

初识grpc

gRPC 特性gRPCRESTful API规范必须.proto可选OpenAPI协议HTTP/2任意版本 HTTP有效载荷ProtoBuf(小、二进制)JSON (大、易读)浏览器支持否&#xff08;需要 grpc-web&#xff09;是流传输客户端、服务端、双向客户端、服务端代码生成是OpenAPI 第三工具gRPC 远程过程调用 &…

九、MySQL 常用函数汇总(2)

文章目录一、条件判断函数1.1 IF(expr,v1,v2)函数1.2 IFNULL(v1,v2)函数1.3 CASE函数二、系统信息函数2.1 获取MySQL版本号、连接数和数据库名的函数2.2 获取用户名的函数2.3 获取字符串的字符集和排序方式的函数2.4 获取最后一个自动生成的ID值的函数三、加密函数3.1 加密函数…

C进阶:动态内存函数 malloc calloc realloc free及常见动态内存开辟错误

本文主要讲解动态内存开辟的有关知识。 目录 一.malloc 与 free 1.malloc 2.free 3.实例&#xff1a; 二.calloc 三.realloc 四.常见的动态内存错误 1.对NULL指针的解引用操作 2.对动态开辟空间的越界访问 3.对非动态开辟内存使用free释放 4.使用free释放一块动态…

linux基本功系列之pwd命令实战

本文目录 文章目录一. pwd命令介绍二. 语法格式及常用选项2.1 语法格式2.2 常用参数三. 参考案例3.1 显示所在目录的完整路径3.2 显示符号链接的路径 -P 参数3.3 查看上一次所在的工作目录3.4 查看PWD的版本四. pwd的命令类型总结前言&#x1f680;&#x1f680;&#x1f680; …

React--》超详细教程——React脚手架的搭建与使用

目录 React脚手架的创建 全局安装创建 npx安装创建(官方推荐) 指定React版本安装 脚手架文件介绍 React脚手架是开发现代Web应用的必备&#xff0c;其充分利用Webpack、Babel、ESlint等工具辅助项目的开发&#xff0c;当然这些工具也无需手动配置即可使用&#xff0c;脚手…

结构分析软件:2D Frame Analysis 7.2.6 Crack

结构分析软件&#xff1a;2D Frame Analysis 7.2.6 用于在静态、动态、线性和非线性载荷下对框架、梁和桁架进行结构分析的软件工具。它包括静态版和桁架版的所有功能 2D 框架分析软件套件以及处理动态负载的能力。自动计算结构的动态模态&#xff0c;并以图形方式表示相应的模…