MySQL中InnoDB引擎如何对索引的扩展
发表于:2025-01-23 作者:千家信息网编辑
千家信息网最后更新 2025年01月23日,MySQL中InnoDB引擎如何对索引的扩展,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。InnoDB引擎对索引的扩展,自动追加主键值及
千家信息网最后更新 2025年01月23日MySQL中InnoDB引擎如何对索引的扩展
MySQL中,使用InnoDB引擎的每个表,创建的普通索引(即非主键索引),都会同时保存主键的值。 比如语句 创建了t1表,其主键为(i1, i2),同时创建了基于d列的索引k_d,但其实在底层,InnoDB引擎将索引k_d扩展成(d,i1,i2)。 InnoDB引擎这么做,是用空间换性能,优化器在判断是否使用索引及使用哪个索引时会有更多列参考,这样可能生成更高效的执行计划,获得更好的性能。 优化器在ref、range和index_merge类型的访问,Loose Index Scan访问,连接和排序优化, MIN()/MAX()优化时使都会使用扩展列。 我们来看个例子: 在普通索引中追加扩展主键是InnoDB在底层做的,show index等语句不显示追加列,但我们可以通过其它方式来验证。看这个SQL 如果InnoDB没有扩展索引,索引k_d为(d),生成的执行计划应该类似这样,使用k_d索引找到d为'2000-01-01'的5行数据,再回表过滤出i1为3的,最后计算count。或者使用主键索引找到i1为3的5行数据,再回表过滤出d为'2000-01-01'的,最后计算count。下面仅示意走k_d索引的情况: 如果InnoDB扩展了索引,索引k_d为(d,i1,i2),这时,优化器可以使用最左边的索引前缀(d,i1),生成的执行计划应该类似这样,使用k_d索引找到d为'2000-01-01'及i1为3的1行数据,然后计算count 并且d列是DATE类型占4个字节,i1是INT类型占4个字节,所以查询中使用的键值长度就是8个字节(key_len: 8)。 我们看看实际生成的执行计划 果然跟我们的判断一致,注意执行计划中的细节:
InnoDB引擎底层扩展普通索引的情况,也可以通过跟MyISAM引擎对比来进行旁证: 可以看到,同样的结构同样的数据,因为MyISAM引擎不会在底层自动扩展普通索引,所以执行计划还是通过主键索引进行处理。 按照官方手册的说明,也可以用SHOW STATUS命令来验证 Handler_read_next表示在进行索引扫描时,按照索引从数据文件里取数据的次数。使用MyISAM引擎的t1myisam表,Handler_read_next值为5,使用InnoDB引擎的t1表,Handler_read_next值减小到1,就是因为InnoDB引擎对索引进行了主键扩展,读取的次数少,效率更好。 默认情况下,优化器分析InnoDB表的索引时会考虑扩展列,但如果因为特殊原因让优化器不考虑扩展列,可以使用SET optimizer_switch = 'use_index_extensions=off'设置。
MySQL中InnoDB引擎如何对索引的扩展,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
InnoDB引擎对索引的扩展,自动追加主键值及其对执行计划的影响。
CREATE TABLE t1 (
i1 INT NOT NULL DEFAULT 0,
i2 INT NOT NULL DEFAULT 0,
d DATE DEFAULT NULL,
PRIMARY KEY (i1, i2),
INDEX k_d (d)
) ENGINE = InnoDB;
root@database-one 15:15: [gftest]> CREATE TABLE t1 (
-> i1 INT NOT NULL DEFAULT 0,
-> i2 INT NOT NULL DEFAULT 0,
-> d DATE DEFAULT NULL,
-> PRIMARY KEY (i1, i2),
-> INDEX k_d (d)
-> ) ENGINE = InnoDB;
Query OK, 0 rows affected (0.06 sec)
root@database-one 15:15: [gftest]> INSERT INTO t1 VALUES
-> (1, 1, '1998-01-01'), (1, 2, '1999-01-01'),
-> (1, 3, '2000-01-01'), (1, 4, '2001-01-01'),
-> (1, 5, '2002-01-01'), (2, 1, '1998-01-01'),
-> (2, 2, '1999-01-01'), (2, 3, '2000-01-01'),
-> (2, 4, '2001-01-01'), (2, 5, '2002-01-01'),
-> (3, 1, '1998-01-01'), (3, 2, '1999-01-01'),
-> (3, 3, '2000-01-01'), (3, 4, '2001-01-01'),
-> (3, 5, '2002-01-01'), (4, 1, '1998-01-01'),
-> (4, 2, '1999-01-01'), (4, 3, '2000-01-01'),
-> (4, 4, '2001-01-01'), (4, 5, '2002-01-01'),
-> (5, 1, '1998-01-01'), (5, 2, '1999-01-01'),
-> (5, 3, '2000-01-01'), (5, 4, '2001-01-01'),
-> (5, 5, '2002-01-01');
Query OK, 25 rows affected (0.01 sec)
Records: 25 Duplicates: 0 Warnings: 0
root@database-one 15:21: [gftest]> show index from t1;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| t1 | 0 | PRIMARY | 1 | i1 | A | 5 | NULL | NULL | | BTREE | | |
| t1 | 0 | PRIMARY | 2 | i2 | A | 25 | NULL | NULL | | BTREE | | |
| t1 | 1 | k_d | 1 | d | A | 5 | NULL | NULL | YES | BTREE | | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.01 sec)
SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'
mysql> EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
type: ref
possible_keys: PRIMARY,k_d
key: k_d
key_len: 4
ref: const
rows: 5
Extra: Using where; Using index
mysql> EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
type: ref
possible_keys: PRIMARY,k_d
key: k_d
key_len: 8
ref: const,const
rows: 1
Extra: Using index
root@database-one 15:35: [gftest]> EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: ref
possible_keys: PRIMARY,k_d
key: k_d
key_len: 8
ref: const,const
rows: 1
filtered: 100.00
Extra: Using index
1 row in set, 1 warning (0.01 sec)
key_len从4字节变为8字节,表明键查找使用列d和i1,而不仅仅是d。
ref从const更改为const,const,表明查找使用两个键值,而不是一个。
rows从5减少到1,表明检索更少的行。
Extra从Using where; Using index改为Using index,表示只用索引读取,不必回表。
root@database-one 16:07: [gftest]> CREATE TABLE t1MyISAM (
-> i1 INT NOT NULL DEFAULT 0,
-> i2 INT NOT NULL DEFAULT 0,
-> d DATE DEFAULT NULL,
-> PRIMARY KEY (i1, i2),
-> INDEX k_d (d)
-> ) ENGINE = MyISAM;
Query OK, 0 rows affected (0.01 sec)
root@database-one 16:07: [gftest]> INSERT INTO t1myisam VALUES
-> (1, 1, '1998-01-01'), (1, 2, '1999-01-01'),
-> (1, 3, '2000-01-01'), (1, 4, '2001-01-01'),
-> (1, 5, '2002-01-01'), (2, 1, '1998-01-01'),
-> (2, 2, '1999-01-01'), (2, 3, '2000-01-01'),
-> (2, 4, '2001-01-01'), (2, 5, '2002-01-01'),
-> (3, 1, '1998-01-01'), (3, 2, '1999-01-01'),
-> (3, 3, '2000-01-01'), (3, 4, '2001-01-01'),
-> (3, 5, '2002-01-01'), (4, 1, '1998-01-01'),
-> (4, 2, '1999-01-01'), (4, 3, '2000-01-01'),
-> (4, 4, '2001-01-01'), (4, 5, '2002-01-01'),
-> (5, 1, '1998-01-01'), (5, 2, '1999-01-01'),
-> (5, 3, '2000-01-01'), (5, 4, '2001-01-01'),
-> (5, 5, '2002-01-01');
Query OK, 25 rows affected (0.02 sec)
Records: 25 Duplicates: 0 Warnings: 0
root@database-one 16:07: [gftest]> EXPLAIN SELECT COUNT(*) FROM t1myisam WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1myisam
partitions: NULL
type: ref
possible_keys: PRIMARY,k_d
key: PRIMARY
key_len: 4
ref: const
rows: 4
filtered: 16.00
Extra: Using where
1 row in set, 1 warning (0.01 sec)
root@database-one 16:12: [gftest]> FLUSH TABLE t1;
Query OK, 0 rows affected (0.00 sec)
root@database-one 16:12: [gftest]> FLUSH STATUS;
Query OK, 0 rows affected (0.14 sec)
root@database-one 16:12: [gftest]> SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01';
+----------+
| COUNT(*) |
+----------+
| 1 |
+----------+
1 row in set (0.03 sec)
root@database-one 16:12: [gftest]> SHOW STATUS LIKE 'handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 0 |
| Handler_read_key | 1 |
| Handler_read_last | 0 |
| Handler_read_next | 1 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
+-----------------------+-------+
7 rows in set (0.01 sec)
root@database-one 16:13: [gftest]> FLUSH TABLE t1myisam;
Query OK, 0 rows affected (0.01 sec)
root@database-one 16:13: [gftest]> FLUSH STATUS;
Query OK, 0 rows affected (0.00 sec)
root@database-one 16:13: [gftest]> SELECT COUNT(*) FROM t1myisam WHERE i1 = 3 AND d = '2000-01-01';
+----------+
| COUNT(*) |
+----------+
| 1 |
+----------+
1 row in set (0.01 sec)
root@database-one 16:13: [gftest]> SHOW STATUS LIKE 'handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 0 |
| Handler_read_key | 1 |
| Handler_read_last | 0 |
| Handler_read_next | 5 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 0 |
+-----------------------+-------+
7 rows in set (0.00 sec)
root@database-one 16:26: [gftest]> SET optimizer_switch = 'use_index_extensions=off';
Query OK, 0 rows affected (0.01 sec)
root@database-one 16:26: [gftest]> EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: ref
possible_keys: PRIMARY,k_d
key: PRIMARY
key_len: 4
ref: const
rows: 5
filtered: 20.00
Extra: Using where
1 row in set, 1 warning (0.02 sec)
看完上述内容,你们掌握MySQL中InnoDB引擎如何对索引的扩展的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!
索引
引擎
数据
字节
普通
底层
生成
情况
更多
类型
内容
原因
可以通过
同时
就是
性能
方法
次数
语句
问题
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
辅警网络安全考试
网络安全意识洼地
lol最搞笑的游戏服务器
系统服务器的容量有多大
远程连接数据库 端口
计算机网络技术之父
筹款软件开发
南京吉同信网络技术
成都网络安全考试答案
河南阅如网络技术公司
选修卷 网络技术应用
esi 数据库是什么
承德1u机架式服务器厂家
华为服务器业务出售可能买家
网络安全等级一体化服务
山东省浪潮服务器代理商
postgres数据库如何启动
数据库字段命名可以是关键字吗
原神私人服务器下载教程手机版
计算机网络技术五年学年鉴定表
java 操作数据库的代码
网络安全领导必要性
工业网络技术应聘什么职位
proxy代理服务器地址
苏州项目软件开发优势
软件开发后续维护费
手游tft账号能改服务器吗
鸿新大真网络技术
学软件开发的培训学校
宿州直播平台软件开发定制