MySQL复合主键表执行DESCRIBE TABLE为何仅显示单个主键被使用?
我用SQLAlchemy在MySQL中创建了多对多关联的Projects表和Tags表,关联表projects_tags的结构如下:
mysql> describe projects_tags; +-------------+------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+------+------+-----+---------+-------+ | projects_id | int | NO | PRI | NULL | | | tags_id | int | NO | PRI | NULL | | +-------------+------+------+-----+---------+-------+
该表的projects_id和tags_id共同构成复合主键,且外键关系已配置完成:
mysql> select * from INFORMATION_SCHEMA.TABLE_CONSTRAINTS where CONSTRAINT_TYPE = 'FOREIGN KEY'; +--------------------+-------------------+----------------------+--------------+---------------+-----------------+----------+ | CONSTRAINT_CATALOG | CONSTRAINT_SCHEMA | CONSTRAINT_NAME | TABLE_SCHEMA | TABLE_NAME | CONSTRAINT_TYPE | ENFORCED | +--------------------+-------------------+----------------------+--------------+---------------+-----------------+----------+ | def | uv | projects_tags_ibfk_1 | uv | projects_tags | FOREIGN KEY | YES | | def | uv | projects_tags_ibfk_2 | uv | projects_tags | FOREIGN KEY | YES | +--------------------+-------------------+----------------------+--------------+---------------+-----------------+----------+
表功能正常,但执行以下命令时结果让我困惑:
mysql> describe table projects_tags; +----+-------------+---------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+ | 1 | SIMPLE | projects_tags | NULL | index | NULL | tags_id | 4 | NULL | 1 | 100.00 | Using index | +----+-------------+---------------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
结果里key字段只显示复合主键的一半tags_id,且key_len=4说明只用到了一个主键字段。请问这是什么原因?为什么describe [table_name]和describe table [table_name]的结果差异这么大?
1. 两个命令的本质差异
MySQL里的describe [table_name](或简写desc)是查看表结构的命令,等价于show columns from [table_name],返回的是表的字段定义、约束类型等元数据。
而describe table [table_name]是explain table [table_name]的别名,MySQL会将其解析为explain select * from projects_tags——它的作用是生成查询执行计划,和查看表结构完全是两回事,这就是两者结果天差地别的核心原因。
2. 执行计划中key: tags_id的原因
你的projects_tags表实际存在三个索引:
- 复合主键索引
PRIMARY,包含projects_id和tags_id两个字段; - 两个外键自动生成的单独索引:
projects_id索引、tags_id索引(MySQL创建外键时,若字段无对应索引会自动创建普通索引)。
当执行select * from projects_tags时,MySQL会选择效率最高的方式完成查询:全索引扫描比全表扫描更快,而tags_id单独索引的长度(4字节)比复合主键索引(8字节)更小,扫描时开销更低,因此MySQL选择了这个索引来覆盖查询。
这是MySQL的正常优化行为,完全不影响复合主键的唯一性约束,也不会破坏外键关联功能——你的表依然能正确维护Projects和Tags的多对多关系。
内容的提问来源于stack exchange,提问作者David Stein

