大家好,我是程序员啊粥。

今天给大家分享一个我遇到过的比较少见的面试题,那就是 MySQL 中如何计算一个索引的长度。

说实话,我第一次遇到这个问题的时候想当然的以为索引长度就是我们建表时定义的字段长度,如果是联合索引,那就是多个字段长度相加。

事实证明,在我说出上述回答之后,面试官就让我带着简历跑路了。

于是乎,我仔细查阅了相关资料,发现索引长度这个计算方式还是有点意思的,索性给大家分享一下。

首先,我们要知道 MySQL Innodb 引擎对于索引的长度是有限制的,最大为 767 字节。

你采用不同的字符编码方式,对应的字节数是不一样的,比如我们最常用的 utf8mb4 字符集是 4 字节字符集,则 767 字节 / 4 字节每字符 = 191字符(默认索引最大长度),所以在 varchar(255) 或 char(255) 类型字段上创建索引会失败,报错会提示最大索引长度为 767 字节。

其他的一些编码方式对应关系分别是:latin1 编码的,一个字符占用一个字节,gbk 编码的,一个字符占用两个字节,utf8 编码的,一个字符占用三个字节。

总的来说,索引长度计算规则为:

  1. 所有的索引字段,如果没有设置 Not Null,则需要加一个字节(这也是我们为什么建议建表时不要有 Null 字段的原因之一)。

  2. 对于定长字段,int 类型占四个字节、date 占三个字节、char(n) 占 N 个字符。

  3. 对于变成字段 varchar(n),则是 N 个字符 + 两个字节。

  4. 不同的字符集,一个字符占用的字节数不同。latin1编码的,一个字符占用一个字节,gbk编码的,一个字符占用两个字节,utf8编码的,一个字符占用三个字节。

  5. 索引长度 char()、varchar() 索引长度的计算公式:

Character Set:utf8mb4=4,utf8=3,gbk=2,latin1=1) * 列长度 + 1(允许 Null) + 2(变长列)

基于以上原则,我们建张表来验证下:

CREATE TABLE `tb_item` (
`id` bigint NOT NULL COMMENT '书籍id,同时也是书籍编号',
`title` varchar(100) NOT NULL COMMENT '书籍名称',
`sell_point` varchar(500) DEFAULT NULL COMMENT '书籍卖点',
`price` bigint NOT NULL COMMENT '书籍价格,单位为:分',
`num` int NOT NULL COMMENT '库存数量',
`barcode` varchar(30) DEFAULT NULL COMMENT '书籍条形码',
`image` varchar(500) DEFAULT NULL COMMENT '书籍图片',
`cid` bigint NOT NULL COMMENT '所属类目,叶子类目',
`status` tinyint NOT NULL DEFAULT '1' COMMENT '书籍状态,1-正常,2-下架,3-删除',
`created` datetime NOT NULL COMMENT '创建时间',
`updated` datetime NOT NULL COMMENT '更新时间',
`upload_id` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `cid` (`cid`),
KEY `status` (`status`),
KEY `updated` (`updated`),
KEY `tb_item_title_price_num` (`title`,`price`,`num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='书籍表';

在这张表上我们建立了联合索引 tb_item_title_price_num ,由三个字段组成,分别是变长字段 varchar,定长字段 price 以及 num。

我们先来执行如下这条语句:

explain select * from tb_item where title = '编译原理' and price = 45 and num = 23232;

我们看到 key 是 tb_item_title_price_num,同时索引长度 key_len 为 314 ,证明是使用到了联合索引 tb_item_title_price_num 的三个完整字段的。

这个 314 的具体计算方式为:

字符集我们建表时用的为 utf8 编码,所以 title 字段的索引长度是 3 * 100 + 0 + 2 = 302,price 字段的索引长度是 8,num 字段的索引长度是 4。

因此 tb_item_title_price_num 索引总共长度是 302 + 8 + 4 = 314。

为了验证我们的计算方式,接下来我们再执行如下语句,使得索引部分失效。

explain select * from tb_item where title = '编译原理' and num = 23232

这条语句因为我们跳过了 price 字段,所以联合索引中只会有 title 字段生效,剩余部分都会失效,如果我们计算方式没有问题的话,那么此时执行计划中的 key_len 应该为 302。

果然,我们看到 key_len 已经变成了 302,这意味着索引部分失效了,只有 title 字段索引起了作用,同时 Extra 为 Using index condition,说明使用了索引,但是需要回表查询数据。

具体 explain 执行计划中其他字段的具体含义,参考这篇文章。

好了,我们今天的内容就到这里了。

简单总结一下,在 MySQL 中,索引长度不仅取决于我们建表时设置的字段长度,还和具体的字符集编码以及字段是否允许为 Null 等多个条件相关,字段长度只能作为索引长度的预估项,而不是准确值。

我是程序员啊粥,关注我,我们一起在技术海洋中向上生长。

搞定面试官 - MySQL 中你知道如何计算一个索引的长度嘛?的更多相关文章

  1. 搞定面试官 - 你可以介绍一下在 MySQL 中,哪些情况下 索引会失效嘛?

    大家好,我是程序员啊粥,前边给大家分享了 *MySQL InnoDB 索引模型 在 MySQL InnoDB 中,为什么 delete 删除数据之后表数据文件大小没有变 如何计算一个索引的长度 如何查 ...

  2. RabbitMQ:从入门到搞定面试官

    安装 使用docker安装,注意要安装tag后缀为management的镜像(包含web管理插件),我这里使用的是rabbitmq:3.8-management 1. 拉取镜像 shell docke ...

  3. 搞定面试官 - 可以介绍一下在 MySQL 中你平时是怎么使用 COUNT() 的嘛?

    大家好,我是程序员啊粥. 相信在大家的工作中,有很多的功能都需要用到 count(*) 来统计表中的数据行数.同时,对于一些大数据的表,用 count 都是瑟瑟发抖,往往会结合缓存等进行处理. 那么, ...

  4. 【搞定面试官】谈谈你对JDK中Executor的理解?

    ## 前言 随着当今处理器计算能力愈发强大,可用的核心数量越来越多,各个应用对其实现更高吞吐量的需求的不断增长,多线程 API 变得非常流行.在此背景下,Java自JDK1.5 提供了自己的多线程框架 ...

  5. 金三银四,2018最新iOS面试题,由它可以搞定面试官?

    序言 这些资料,你一定会用到!我相信很多人都在说,iOS行业不好了,iOS现在行情越来越难了,失业的人比找工作的人还要多.失业即相当于转行,跳槽即相当于降低自己的身价.那么做iOS开发的你,你是否在时 ...

  6. 【搞定面试官】try中有return,finally还会执行吗?

    本篇文章我们主要探讨 一下如果try {}语句中有return,这种情况下finally语句还会执行吗?其实JVM规范是对这种情况有特殊规定的,那我就先上代码吧! public class Final ...

  7. 【搞定面试官】- Synchronized如何实现同步?锁优化?(1)

    前言 说起Java面试中最高频的知识点非多线程莫属.每每提起多线程都绕不过一个Java关键字--synchronized.我们都知道该关键字可以保证在同一时刻,只有一个线程可以执行某个方法或者某个代码 ...

  8. 搞定面试官:咱们从头到尾再说一次 Java 垃圾回收

    接着前几天的两篇文章,继续解析JVM面试问题,送给年后想要跳槽的小伙伴 万万没想到,面试中,连 ClassLoader类加载器 也能问出这么多问题..... 万万没想到,JVM内存区域的面试题也可以问 ...

  9. 【搞定面试官】你还在用Executors来创建线程池?会有什么问题呢?

    前言 上文我们介绍了JDK中的线程池框架Executor.我们知道,只要需要创建线程的情况下,即使是在单线程模式下,我们也要尽量使用Executor.即: ExecutorService fixedT ...

随机推荐

  1. Navicat破解激活流程

    ​​ ​ Navicat Navicat Premium 是一套数据库开发工具,让你从单一应用程序中同时连接 MySQL.MariaDB.MongoDB.SQL Server.Oracle.Postg ...

  2. 初识 Redis 以及其基本使用方法

     1.什么是Redis  redis 是一个高性能的key-value数据库,它支持的类型更多 包括 string(字符串).list(链表).set(集合).zset(sorted set --有序 ...

  3. ML第5周学习小结

    本周收获 总结一下本周学习内容: 1.学习了<深入浅出Pandas>的第五章:Pandas高级操作的两个内容 数据迭代 函数应用 我的博客链接: pandas:数据迭代.函数应用 2.&l ...

  4. SQL的语法

    SQL的语法 SQL通用语法 SQL语句可以单行或多行书写,以分号(";")结尾. SQL语句可以使用空格或缩进增强可读性. MySQL数据库的SQL语句不区分大小写(建议关键字大 ...

  5. Linux(Centos7)静默安装Oracle19C

    Oracle数据库服务器一般都是Linux,Linux服务器一般都是在非图形界面的操作,本文章手把手教你如何在非图形界面安装Oracle19C. ORACLE 19C 的安装包自行在官网下载,下载免费 ...

  6. Nginx安装及支持https代理配置和禁用TSLv1.0、TSLv1.1配置

    Linux安装Nginx Nginx安装及支持https代理配置和禁用TSLv1.0.TSLv1.1配置. 下载安装包 [root@localhost ~]# wget http://nginx.or ...

  7. 代码调用Rally的接口介绍

    1. 支持的语言 2. 创建APIKey 3. GetRequest 4. QueryRequest 5. CreateRequest 6. 参考资料 本文链接: https://www.cnblog ...

  8. Mac安装Brew包管理系统

    Mac安装Brew包管理系统 前言 为什么需要安装brew 作为一个开发人员, 习惯了使用centos的yum和ubuntu的apt, 在mac中有没有这两个工具的平替? 有, 就是Brew. Bre ...

  9. 《Stepwise Metric Promotion for Unsupervised Video Person Re-identification》 ICCV 2017

    Motivation: 这是ICCV 17年做无监督视频ReID的一篇文章.这篇文章简单来说基于两个Motivation. 在不同地方或者同一地方间隔较长时间得到的tracklet往往包含的人物是不同 ...

  10. 【cartogarpher_ros】一: ros系统下的快速安装

    Cartographer是一个跨多个平台和传感器配置提供 2D 和 3D实时同步定位和映射 ( SLAM ) 的系统. 使用Cartographer有Ros集成环境和无Ros环境,对于新手快速入门,推 ...