作者:姚远

MySQL ACE,华为云 MVP ,专一于 Oracle、MySQL 数据库多年,Oracle 10G 和 12C OCM,MySQL 5.6,5.7,8.0 OCP。当初鼎甲科技任技术顾问,为共事和客户提供数据库培训和技术支持服务。

本文起源:原创投稿

*爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。


当在很长的字符串的字段上创立索引时,索引会变得很大而且低效,一个解决办法是 crc32 或 md5 函数对长字符串进行哈希计算,而后在计算的后果上创立索引。在 MySQL 5.7 当前的版本,能够创立一个主动生成的字段,例如能够创立上面一个表:

create table website(id int unsigned not null,web varchar(100) not null,webcrc int unsigned generated always as (crc32(web)) not null,primary key (id));

向这个表中插入记录:

mysql> insert into website(id,web) values(1,"https://www.scutech.com");Query OK, 1 row affected (0.07 sec)mysql> select * from website;+----+-------------------------+-----------+| id | web                     | webcrc    |+----+-------------------------+-----------+|  1 | https://www.scutech.com | 851176738 |+----+-------------------------+-----------+1 row in set (0.00 sec)

能够看到字段 webcrc 中主动生成了 web 字段的循环冗余校验值,在这个字段上创立索引,能够失去一个占用空间少,而且高效的索引。

在 MySQL 8.0.13 当前的版本,能够间接创立函数索引,例如:

create table website8(id int unsigned not null,web varchar(100) not null,primary key (id),index ((crc32(web))));

查问这个表上的索引:

mysql> show index from website8\G*************************** 1. row ***************************        Table: website8   Non_unique: 0     Key_name: PRIMARY Seq_in_index: 1  Column_name: id    Collation: A  Cardinality: 0     Sub_part: NULL       Packed: NULL         Null:   Index_type: BTREE      Comment:Index_comment:      Visible: YES   Expression: NULL*************************** 2. row ***************************        Table: website8   Non_unique: 1     Key_name: functional_index Seq_in_index: 1  Column_name: NULL    Collation: A  Cardinality: 0     Sub_part: NULL       Packed: NULL         Null:   Index_type: BTREE      Comment:Index_comment:      Visible: YES   Expression: crc32(`web`)2 rows in set (0.00 sec)

能够看到第一个索引是主键,第二个索引是函数索引。

解决索引字段长的另一个方法是创立前缀索引(prefix index),前缀索引的创立语法是:col_name(length),前缀索引是对字符串的后面一部分创立索引,反对的数据类型包含:CHAR、VARCHAR、BINARY 和 VARBINARY。创立前缀索引的要害是抉择前缀的字符串的长度,长度越长,索引的选择性越高,但存储的空间也越大。

sbtest2 表中 c 字段是 120 长度的字符串,上面的 SQL 语句查问在不同长度时索引的选择性:

mysql> selectcount(distinct(left(c,3)))/count(*) sel3,count(distinct(left(c,7)))/count(*) sel7,count(distinct(left(c,9)))/count(*) sel9,count(distinct c)/count(*) selectivityfrom sbtest1;+--------+--------+--------+-------------+| sel3   | sel7   | sel9   | selectivity |+--------+--------+--------+-------------+| 0.0120 | 0.9959 | 1.0000 |      1.0000 |+--------+--------+--------+-------------+1 row in set (1.66 sec)

能够看到在这个字段的前 9 位创立索引即可达到 1 的选择性,再减少这个索引的前缀位数,索引的选择性并不会进步,上面是创立索引的命令:

mysql> alter table sbtest2 add index (c(9));