MySQL Varchar前缀索引的一个细节

在线上环境中,对一个varchar类型的字段做索引的时候,如果这个字段的长度太长,我们经常会用到前缀索引。

使用前缀索引有2个好处:

1、前缀索引的存在,使得整个索引的数据量变小;
2、在insert数据的时候,维护索引的速度变快,insert操作的效率也会提升。

例如,下面是一个前缀索引的例子,我们对name列的前10个字段做了个索引。

注意:以下测试版本都是MySQL8.0.12

CREATE TABLE `test` (
  `id` int(11) DEFAULT NULL,
  `val` int(11) DEFAULT NULL,
  `name` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
ALTER TABLE test ADD INDEX idx_name (name ( 10 ));
CREATE TABLE `test` (
  `id` int(11) DEFAULT NULL,
  `val` int(11) DEFAULT NULL,
  `name` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  KEY `idx_name` (`name`(10))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

在MySQL中,前缀索引的长度是有一定限制的。我们将name字段上的索引修改成name(1000),看看结果:

mysql> ALTER TABLE test DROP INDEX idx_name;
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE test ADD INDEX idx_name (name ( 1000 ));
1071 - Specified key was too long; max key length is 3072 bytes
mysql> show warnings;
+-------+------+----------------------------------------------------------+
| Level | Code | Message                                                  |
+-------+------+----------------------------------------------------------+
| Error | 1071 | Specified key was too long; max key length is 3072 bytes |
+-------+------+----------------------------------------------------------+
1 row in set (0.04 sec)

可以看到,出现1个warning,信息是这个前缀索引太长了。最长长度是3072个字节。

mysql> ALTER TABLE test ADD INDEX idx_name (name ( 769 ));
1071 - Specified key was too long; max key length is 3072 bytes
mysql> ALTER TABLE test ADD INDEX idx_name (name ( 768 ));
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0
CREATE TABLE `test` (
  `id` int(11) DEFAULT NULL,
  `val` int(11) DEFAULT NULL,
  `name` varchar(2000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  KEY `idx_name` (`name`(768))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

可以看到name列前缀索引长度修改为769失败了,而修改为768成功了,本质原因其实是3072个字节,采用utf8mb4编码,对应的字符数量就是3072/4,也就是768

若编码是utf8就除3

mysql> ALTER TABLE test ADD INDEX idx_name (name ( 1025 ));
1071 - Specified key was too long; max key length is 3072 bytes
mysql> ALTER TABLE test ADD INDEX idx_name (name ( 1024 ));
Query OK, 0 rows affected (0.11 sec)
Records: 0  Duplicates: 0  Warnings: 0
CREATE TABLE `test`  (
  `id` int(11) NULL DEFAULT NULL,
  `val` int(11) NULL DEFAULT NULL,
  `name` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  INDEX `idx_name`(`name`(1024)) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

经过查询官方文档,得到正确答案:

Prefix support and lengths of prefixes (where supported) are storage engine dependent. For example, a prefix can be up to 767 bytes long for InnoDB tables that use the REDUNDANT or COMPACT row format. The prefix length limit is 3072 bytes for InnoDB tables that use the DYNAMIC or COMPRESSED row format. For MyISAM tables, the prefix length limit is 1000 bytes.

也就是说,对于Innodb来说,redundant或者compact类型的行格式,默认最大前缀索引长度是767;dynamic或者compressed行格式,默认的最大前缀索引长度是3072;
对于MyISAM来讲,最大前缀索引长度是1000。

我们看下test表的行格式:

mysql> SELECT * FROM information_schema.TABLES WHERE	table_name = 'test';
+---------------+--------------+------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------------+
| TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME | TABLE_TYPE | ENGINE | VERSION | ROW_FORMAT | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH | MAX_DATA_LENGTH | INDEX_LENGTH | DATA_FREE | AUTO_INCREMENT | CREATE_TIME         | UPDATE_TIME | CHECK_TIME | TABLE_COLLATION    | CHECKSUM | CREATE_OPTIONS | TABLE_COMMENT |
+---------------+--------------+------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------------+
| def           | laravel      | test       | BASE TABLE | InnoDB |      10 | Dynamic    |         11 |           1489 |       16384 |               0 |            0 |         0 | NULL           | 2022-07-21 16:10:05 | NULL        | NULL       | utf8mb4_general_ci | NULL     |                |               |
| def           | test         | test       | BASE TABLE | InnoDB |      10 | Dynamic    |      15756 |            100 |     1589248 |               0 |      1589248 |         0 | NULL           | 2021-12-28 11:34:43 | NULL        | NULL       | utf8_general_ci    | NULL     |                | 测试表        |
+---------------+--------------+------------+------------+--------+---------+------------+------------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+--------------------+----------+----------------+---------------+
2 rows in set (0.06 sec)

可以看到,这个行格式是Dynamic,当然,最大索引长度就是3072了。
MySQL默认的行格式就是Dynamic,其他格式的,这里不再测试。

原文地址

### 回答1: 在 MySQL 中创建前缀索引可以使用以下语句: ``` CREATE INDEX index_name ON table_name (column_name(length)); ``` 其中,index_name 是索引的名称,table_name 是表的名称,column_name 是要创建索引的列,length 是前缀长度。 例如,在名为 "customers" 的表中创建名为 "name_index" 的前缀索引,并且前缀长度为 10,可以使用以下语句: ``` CREATE INDEX name_index ON customers (name(10)); ``` 注意,前缀索引只对 VARCHAR 或 CHAR 类型的列有效 ### 回答2: 在MySQL中创建前缀索引的方法如下: 首先,选择需要创建前缀索引的表和列。假设我们要在名为"users"的表中的"username"列上创建前缀索引。 接下来,我们使用以下语法创建前缀索引: ALTER TABLE users ADD INDEX prefix_username (username(5)); 在上述语法中,"username(5)"表示我们要对"username"列的前5个字符创建索引。你可以根据实际需要选择合适的前缀长度。 创建索引后,MySQL将使用该索引快对该列的检索速度。但要注意,使用前缀索引可能会导致查询结果的准确性下降。例如,如果我们使用前缀索引来进行模糊搜索,那么可能会返回一些不符合我们想要的结果。 此外,还可以使用多列前缀索引。例如,我们在"users"表的"username"列和"email"列上创建一个多列前缀索引,可以使用以下语法: ALTER TABLE users ADD INDEX prefix_username_email (username(5), email(10)); 在上述语法中,我们为"username"列选择了前缀长度为5的索引,为"email"列选择了前缀长度为10的索引。 需要注意的是,使用前缀索引可以快查询的速度,但也会增索引的大小。因此,我们应该根据实际需求和性能要求来选择合适的前缀长度。如果前缀长度过长,会导致索引的大小增,从而影响查询的效率。 总而言之,通过在MySQL中创建前缀索引,我们可以快对指定列的检索速度,提高数据库的性能。但在使用前缀索引时需要注意权衡查询结果的准确性和索引大小对性能的影响。 ### 回答3: 在MySQL中创建前缀索引可以提高查询效率和减少索引占用的存储空间。前缀索引是指只使用列值的前缀部分作为索引,而不是使用完整的列值。下面是创建前缀索引的步骤: 1. 使用CREATE INDEX语句创建前缀索引。语法如下: CREATE INDEX 索引名 ON 表名 (列名 (前缀长度)); 2. 索引名可自定义,表名是要创建索引的表名,列名是要创建索引的列名,前缀长度是指要作为索引的列值的前缀长度。 3. 例如,如果要为表名为“students”的“name”列创建前缀索引,只使用姓名的前3个字符作为索引,可以使用以下语句: CREATE INDEX idx_name ON students(name(3)); 4. 前缀长度的选择应根据具体情况。较短的前缀长度可以减少索引的存储空间,但可能引起查询结果的不准确。较长的前缀长度可以更准确地匹配查询条件,但会增索引的存储空间。 5. 创建前缀索引后,可以使用EXPLAIN语句验证索引是否被使用。例如,使用以下语句查询表“students”中“name”列以“J”开头的记录: EXPLAIN SELECT * FROM students WHERE name LIKE 'J%'; 如果索引被使用,查询计划中会显示“Using index”或“Using index condition”。 需要注意的是,前缀索引可能会导致索引选择的不准确性,因此在创建前缀索引时需要谨慎考虑,确保索引的覆盖范围不会过于广泛,以免导致查询结果的不准确。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值