mysql前缀索引 默认长度_如何确定前缀索引的长度?

mysql前缀索引 默认长度_如何确定前缀索引的长度?为什么需要前缀索引问题我们在对一张表里的某个字段或者多个字段建立索引的时候,是否遇到过这个问题。Specifiedkey’uniq_code’wastoolong;maxkeylengthis767bytes.表结构如下:createtable`t_account`(`id`BIGINT(20)UNSIGNEDNOTNULLauto_incrementCOMM…

大家好,又见面了,我是你们的朋友全栈君。

为什么需要前缀索引

问题

我们在对一张表里的某个字段或者多个字段建立索引的时候,是否遇到过这个问题。

Specified key ‘uniq_code’ was too long; max key length is 767 bytes.

表结构如下:

create table `t_account`(

`id` BIGINT(20) UNSIGNED NOT NULL auto_increment COMMENT ‘自增ID’,

`date` varchar(50) NOT NULL DEFAULT ” COMMENT ‘日期’,

`nick_name` varchar(50) NOT NULL DEFAULT ” COMMENT ‘昵称’,

`account` varchar(50) NOT NULL DEFAULT ” COMMENT ‘账号’,

`city` varchar(100) NOT NULL DEFAULT ” COMMENT ‘城市’,

PRIMARY KEY (`id`),

UNIQUE KEY `uniq_code` (`nick_name`,`account`,`city`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=’Test’;

复制代码

原因

在MySQL5.6里默认 innodb_large_prefix=0 限制单列索引长度不能超过767bytes。

在MySQL5.7里默认 innodb_large_prefix=1 解除了767bytes长度限制,但是单列索引长度最大还是不能超过3072bytes。

至于为什么是767字节,是依赖于具体的存储引擎实现的,找了官方文档,也没说为啥。 https://dev.mysql.com/doc/refman/8.0/en/create-index.html

varchar(n)占用几个字节跟字符集有关系:

字符类型若为gbk,每个字符占用2个字节,

字符类型若为utf8,每个字符最多占用3个字节,

字符类型若为utf8mb4,每个字符最多占用4个字节

复制代码

这里我设置的编码为utf8mb4编码,一个字符是占了4个字节,而我创建的索引50+50+100=200字符,总共就是800字节,所以超出了长度。

所以我们经常会见到把字段设置成varchar(255)长度的,在utf8字符集下这个是最大不超过767bytes的长度了,但是并不是一定要设置成varchar(255),还是要根据业务设置每个字段的长度,太长了也不利于我们建立联合索引。

解决办法

可以直接去改字段的长度,或者说,把索引的字段取消掉一些,但是这样改对表本身是不友好的。

通过限定字段的前n个字符为索引,可以通过衡量实际的业务中数据中的长度来取具体的值。

UNIQUE KEY `uniq_code` (`nick_name`(20),`account`(20),`city`(20))

复制代码

表示三个字段取前20字符作为唯一索引,这样的话就是长度就不会超出,这个就是我们说的前缀索引

修改单个索引的最大长度

修改索引限制长度需要在my.ini配置文件中添加以下内容,并重启:

#修改单列索引字节长度为767的限制,单列索引的长度变为3072

innodb_large_prefix=1

但是开启该参数后还需要开启表的动态存储或压缩:

系统变量innodb_file_format为Barracuda

ROW_FORMAT为DYNAMIC或COMPRESSED

复制代码

如何确定前缀索引的长度

上面我们说到可以通过前缀索引来解决索引长度超出限制的问题,但是我们改如何确定索引字段取多长的前缀才合适呢?

这里我们可以通过计算选择性来确定前缀索引的选择性,计算方法如下

全列选择性:

SELECT COUNT(DISTINCT column_name) / COUNT(*) FROM table_name;

某一长度前缀的选择性:

SELECT COUNT(DISTINCT LEFT(column_name, prefix_length)) / COUNT(*) FROM table_name;

当前缀的选择性越接近全列选择性的时候,索引效果越好。

前缀索引的优缺点

占用空间小且快

无法使用前缀索引做 ORDER BY 和 GROUP BY

无法使用前缀索引做覆盖扫描

有可能增加扫描行数

比如身份证加索引,可以加哈希索引或者倒序存储后加前缀索引。

再谈联合索引的创建

当我们不确定在一张表上建立的联合索引应该以哪个字段作为第一列时,上面的创建规则同样适用。

下面这个例子就是在建立customer_id,staff_id的联合索引时进行判断,最终选择(customer_id,staff_id)这样的组合。

# staff_id_selectivity: 0.0001

# customer_id_selectivity: 0.0373

# COUNT(*): 16049

# 通过结果发现,customer_id 的选择性更高,所以应该选择 customer_id 作为联合索引的第一列

SELECT

COUNT(DISTINCT staff_id)/COUNT(*) as staff_id_selectivity,

COUNT(DISTINCT customer_id)/COUNT(*) as customer_id_selectivity,

COUNT(*)

FROM payment

复制代码

所以说

当索引选择性越接近全列选择性的时候,索引效果越好。

也就是用此字段创建索引时,它在这个表的数据里区分度更加明显。

参考

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/143845.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 实体服务是一种反模式

    实体服务是一种反模式

    2022年3月12日
    40
  • verilog经典教程(ps入门教程自学图解)

    Verilog入门1关键字1.1modulemodule()…endmodule代表一个模块,我们的代码写在这个两个关键字中间1.2inputoutputinput关键词,模块的输入信号,比如inputClk,Clk是外面关键输入的时钟信号;output关键词,模块的输出信号,比如output[3:0]Led;这个地方正好是一组输出信号。其中[3:0]表示0~3共4路信号。inout模块输入输出双向信号。数据总线的通信中,这种信号被广泛应用;wire关键词,线信号。例如:w

    2022年4月18日
    47
  • idea 2021激活码_最新在线免费激活

    (idea 2021激活码)本文适用于JetBrains家族所有ide,包括IntelliJidea,phpstorm,webstorm,pycharm,datagrip等。https://javaforall.net/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~0…

    2022年3月28日
    102
  • URL重写:RewriteCond指令与RewriteRule 指令格式

    URL重写:RewriteCond指令与RewriteRule 指令格式Rewirte主要的功能就是实现URL的跳转和隐藏真实地址,基于Perl语言的正则表达式规范。平时帮助我们实现拟静态,拟目录,域名跳转,防止盗链等。本文将针对mod_rewrite和URL匹配的技术细节,以及RewriteCond与RewriteRule指令格式进行探讨。Rew

    2022年5月3日
    38
  • jvm可达性分析算法_对点网络

    jvm可达性分析算法_对点网络作者:张华发表于:2016-04-05版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明(http://blog.csdn.net/quqi99)IP层叫分片,TCP/UDP层叫分段。网卡能做的事(TCP/UDP组包校验和分段,IP添加包头校验与分片)尽量往网卡做,网卡不能做的也尽量迟后分片(发送)或提前合并片(接收)来减少在网络栈中传输和处理的包数目,

    2025年6月14日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号