mysql :select查询字段会导致索引失效吗?
我有一条sql ,不知道为什么会导致索引失效
SELECT
dl.`user_type` AS userType,
dl.`user_name` AS userName,
dl.`phone` AS userPhone,
pc.`name` AS courtName,
dl.`build_unit` AS buildName,
dl.`dev_name` AS deviceName,
dl.`dev_no` AS deviceNo,
dl.`create_time` AS openTime,
dl.`status`
FROM
dev_device_log dl
LEFT JOIN base_project_court pc
ON dl.`court_id` = pc.`id`
ORDER BY dl.`id` DESC
LIMIT 0, 100;
当我注释掉 select 后面的 pc.name
字段就可以使用索引。
不知道为什么,有没有大佬给我解惑一下。
测试环境中dev_device_log
表中只有几百条数据的时候可以走索引,但是我从生产环境随意导出了几万条数据后就无法使用索引了。不太理解为什么select 后面的字段会影响到索引情况表结构:
CREATE TABLE `base_project_court` (
`id` varchar(32) NOT NULL COMMENT '主键id',
`community_id` varchar(32) NOT NULL COMMENT '项目id',
`name` varchar(30) NOT NULL COMMENT '小区名',
`py_name` varchar(120) NOT NULL COMMENT '拼音名',
`logo` varchar(300) DEFAULT NULL COMMENT '小区图标',
`address` varchar(255) DEFAULT NULL COMMENT '小区地址',
`longitude` decimal(10,6) DEFAULT NULL COMMENT '经度(-180,180)',
`latitude` decimal(9,6) DEFAULT NULL COMMENT '纬度(-90,90)',
`status` char(1) NOT NULL DEFAULT '1' COMMENT '状态(1.启用 0.禁用)',
`service_phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
`order_no` smallint(4) NOT NULL DEFAULT '1' COMMENT '排序',
`del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '是否删除',
`create_user` varchar(32) NOT NULL COMMENT '创建人',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_user` varchar(32) NOT NULL COMMENT '更新人',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目小区';
CREATE TABLE `dev_device_log` (
`id` bigint(20) NOT NULL COMMENT 'id',
`community_id` varchar(32) NOT NULL DEFAULT '' COMMENT '项目id',
`court_id` varchar(32) NOT NULL DEFAULT '' COMMENT '小区id',
`build_id` varchar(32) NOT NULL DEFAULT '' COMMENT '楼栋单元id',
`build_unit` varchar(30) NOT NULL DEFAULT '' COMMENT '楼栋单元',
`user_id` varchar(32) NOT NULL DEFAULT '' COMMENT '用户id',
`user_name` varchar(32) NOT NULL DEFAULT '' COMMENT '用户名',
`phone` varchar(15) NOT NULL DEFAULT '' COMMENT '手机号',
`user_type` tinyint(2) NOT NULL DEFAULT '1' COMMENT '用户类型(1.住户 2.物业)',
`device_id` varchar(32) NOT NULL DEFAULT '' COMMENT '设备id',
`dev_name` varchar(32) NOT NULL DEFAULT '' COMMENT '门禁名称',
`dev_no` varchar(10) NOT NULL DEFAULT '' COMMENT '设备编号',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态(1.成功 0.失败)',
`failure_description` varchar(120) NOT NULL DEFAULT '' COMMENT '失败说明',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
我导出了一份几万条脱敏后的数据,但是不知道怎么传上来
我把sql传蓝奏云了,由于蓝奏云不支持上传.sql文件,我先压缩了一个zip包再上传sql文件
回复
1个回答

test
2024-06-19
后面这个 Using index
是表示是用了到了 “覆盖索引”。
从 key 字段可以看出来,使用到了主键索引,然后你的主键是 varchar(32)
,字符集是 utf8mb4
,也就是一个字符占用 4 字节。 32 * 4+ varchar 的前缀长度,也就成了 key_len 里面的 130 了。
在 MySQL 查询数据时,因为每次获取数据都有一个 回表的过程(先找到主键,再去找具体的数据行,你这里就是要去找 pc.name
),这样 MySQL 的优化器就会认为,这样效率太低了,还不如直接全表查询,免得先查询一次主键。
所以当你不获取 pc.name
时,仅仅使用主键索引就足以找到数据了(但是这样在这里的 left join,没有其他筛选的情况下,就有没啥意义了)
我看你是用的 MySQL 5.7,我这里 8.0 ,给 id 和 name 添加一个索引后,也是可以走到索引覆盖的,虽然显示是走了主键。
alter table base_project_court add index idx_id_name (id, name);
回复

适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容