前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >小白学习MySQL - 变通创建索引的案例一则

小白学习MySQL - 变通创建索引的案例一则

作者头像
bisal
发布2021-12-05 09:19:12
4630
发布2021-12-05 09:19:12
举报

前两天同事提了一个问题,MySQL 5.7中给某张表字段增加一个单键值索引,提示了如下错误,

38cf9931785f1567619b91ec7483d79f.png
38cf9931785f1567619b91ec7483d79f.png

一些背景信息,

1. 表设置的字符集,utf8mb4。

2. 表的存储引擎,MyISAM。

3. 表的数据量,1个亿。

4. 执行的SQL,select c1, c2 from test where c1 = :1,c1数据类型是varchar(255),区分度较高,需要创建一个单键值索引。

我们知道,MySQL和Oracle在索引上最大的一个区别,就是索引存在长度的限制。如果是超长键值,可以支持创建前缀的索引,顾名思义,取这个字段的前多少个字符/字节作为索引的键值。

P.S. 《小白学习MySQL - 索引键长度限制的问题

之所以可以定义一个字段前缀作为键值,存储效率是考虑的一个因素,如果列名的前10个字符通常都是不同的,检索这10个字符创建的索引应该会比检索整个列作为索引的效率更高,使用列前缀作为索引会让索引树更小,不仅节省空间,还可能提高插入操作的速度。

对于非二进制的字符串类型(CHAR、VARCHAR、TEXT),前缀会按照字符个数计算,对二进制的字符串类型(BINARY、VARBINARY、BLOB),前缀会按照字节个数计算,因此,当对非二进制的字符串列明确前缀长度的时候,需要考虑多字节字符集的因素。

MySQL官方手册索引的章节提到了,前缀索引长度限制是和引擎相关的,如果用的是InnoDB,前缀上限是767字节,当启用innodb_large_prefix时,上限可以达到3072字节。如果用的是MyISAM,前缀上限是1000字节,这正是上述创建索引错误提示的内容,

55715d245deafe80a405e94445054b6d.png
55715d245deafe80a405e94445054b6d.png

https://dev.mysql.com/doc/refman/5.7/en/create-index.html

utf8mb4是MySQL 5.5.3之后增加的编码,mb4就是most bytes 4的意思,专门用来兼容四字节的unicode,utf8mb4是utf8的超集。之所以需要utf8mb4,是因为之前的utf8编码最大字符长度为3字节,如果遇到4字节的宽字符就会插入异常了。三个字节的UTF-8最大能编码的Unicode字符是 0xffff,也就是Unicode中的基本多文种平面(BMP)。因此,任何不在基本多文本平面的Unicode字符,都无法使用MySQL的utf8字符集存储,这就包括Emoji表情(Emoji是一种特殊的Unicode 编码,常见于手机上),和很多不常用的汉字,以及任何新增的Unicode字符等(这些都是utf8的缺点)。

InnoDB,如果需要建索引,就不能超过767bytes,utf8编码,255*3=765 bytes,是能建索引情况下的最大值,utf8mb4编码,默认字符长度则应该是767除以4向下取整,就是191。如果设置了innodb_large_prefix,最大长度是3072字节,utf8编码,1024*3=3072 bytes,utf8mb4编码,768*4=3072。

MyISAM,如果需要建索引,就不能超过1000bytes,utf8编码,333*3=999 bytes,是能建索引情况下的最大值,utf8mb4编码,默认字符长度则应该是1000除以4,就是250。

我们可以测下MyISAM,utf8mb4编码表test1,250长度的字段c1,251长度的字段c2,

代码语言:javascript
复制
CREATE TABLE test1 (
  c1 varchar(250),
  c2 varchar(251)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

c1能创建索引,c2创建出错,utf8mb4编码,varchar最大限制250个字符,

代码语言:javascript
复制
/* 可执行 */
create index idx_test1_01 on test1(c1);
/*SQL 错误 [1071] [42000]: Specified key was too long; max key length is 1000 bytes*/
create index idx_test1_02 on test1(c2);

utf8编码表test2,333长度的字段c1,334长度的字段c2,

代码语言:javascript
复制
CREATE TABLE test2 (
  c1 varchar(333),
  c2 varchar(334)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

c1能创建索引,c2创建出错,utf8编码,varchar最大限制333个字符,

代码语言:javascript
复制
/* 可执行 */
create index idx_test2_01 on test2(c1);
/*SQL 错误 [1071] [42000]: Specified key was too long; max key length is 1000 bytes*/
create index idx_test2_02 on test2(c2);

其他场景的测试相近,不再展示。

因此,针对这个问题,可以为c1字段创建一个前缀索引,

代码语言:javascript
复制
create index idx_test_01 on test(c1(250(含)以下的值))

但是1亿数据量,创建非常慢,

d8fbb84d56cab4142109de600f830ebb.png
d8fbb84d56cab4142109de600f830ebb.png

通过沟通,了解到这个需求是检索今年的数据,表中存在时间戳的字段,且今年的数据,是1000多万,如果能改应用SQL,或者只是通过手工执行SQL的前提下,可以有几种解决方案,

1. 如果从原表检索,可以创建一个c1和时间戳字段的复合索引,利用索引扫描,定位所需数据。

2. 如果不需要从原表检索,可以使用时间戳作为条件,通过CTAS,创建一张今年数据的表,通过c1单键值索引,即可定位数据。

参考链接,

https://www.cnblogs.com/l10n/p/12606582.html

https://www.cnblogs.com/biehongli/p/12389418.html

https://www.cnblogs.com/dataoblogs/p/14121929.html

https://www.cnblogs.com/bcxx/p/13671280.html

https://blog.csdn.net/weixin_39372979/article/details/80825606

https://blog.csdn.net/weixin_39926402/article/details/114806819

小白学习MySQL,

小白学习MySQL - “投机取巧”统计表的记录数

小白学习MySQL - 一次慢SQL的定位

小白学习MySQL - TIMESTAMP类型字段非空和默认值属性的影响

小白学习MySQL - 聊聊数据备份的重要性

小白学习MySQL - InnoDB支持optimize table?

小白学习MySQL - table_open_cache的作用

小白学习MySQL - 表空间碎片整理方法

小白学习MySQL - 大小写敏感问题解惑

小白学习MySQL - only_full_group_by的校验规则

小白学习MySQL - max_allowed_packet

小白学习MySQL - mysqldump保证数据一致性的参数差异

小白学习MySQL - 查询会锁表?

小白学习MySQL - 索引键长度限制的问题

小白学习MySQL - MySQL会不会受到“高水位”的影响?

小白学习MySQL - 数据库软件和初始化安装

小白学习MySQL - 闲聊聊

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-12-03 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档