MySQL like查询后置%索引失效分析
表结构
CREATE TABLE `t_food_shop` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`shop_name` varchar(50) NOT NULL DEFAULT '' COMMENT '店铺名称',
`shop_img` varchar(250) NOT NULL DEFAULT '' COMMENT '店铺图片',
`category_name` varchar(50) NOT NULL DEFAULT '' COMMENT '品类名称',
`price` varchar(50) NOT NULL DEFAULT '' COMMENT '消费价格',
`area` varchar(50) NOT NULL DEFAULT '' COMMENT '所属地区',
`collects` bigint(11) NOT NULL DEFAULT '0' COMMENT '收藏的数量',
`shop_type` tinyint(3) NOT NULL DEFAULT '0' COMMENT '店铺的分类(0,蓝丝,1,黄丝)',
`shop_grade` decimal(3,1) NOT NULL DEFAULT '0.0' COMMENT '店铺评级',
`address` varchar(128) NOT NULL DEFAULT '' COMMENT '店铺地址',
`longitude` varchar(16) NOT NULL DEFAULT '' COMMENT '经度',
`latitude` varchar(16) NOT NULL DEFAULT '' COMMENT '纬度',
`geo_hash` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT 'geohash',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`openrice_id` bigint(20) NOT NULL DEFAULT '0' COMMENT 'openrice 店铺唯一id',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_geohash` (`geo_hash`) USING BTREE,
FULLTEXT KEY `idx_name` (`shop_name`) /*!50100 WITH PARSER `ngram` */
) ENGINE=InnoDB AUTO_INCREMENT=673319 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='美食店铺基本数据表';
查询执行计划
EXPLAIN
select id, shop_name, price, collects, shop_grade, address, longitude, latitude from t_food_shop where geo_hash like 'wecny%';
geo_hash字段建立了索引,按照前缀查询,但是索引失效了。
“wecny”字符串长度为5,我们就来看看长度为5的字符串的重复率
select count(1) from t_food_shop;
SELECT (count(*) / 63061 ) percent,count(*) cnt,LEFT(geo_hash,5) prefix
FROM t_food_shop GROUP BY prefix ORDER BY percent DESC LIMIT 0,10;
可以看到,前缀为“wecny”的重复率竟然占到了0.2234,区分度大小了,mysql选择了全表扫描。
我们来试试百分比为0.0338前缀为"wecp3"的执行计划
EXPLAIN
select id, shop_name, price, collects, shop_grade, address, longitude, latitude from t_food_shop where geo_hash like 'wecp3%';
可以看到使用到了idx_geohash索引
结论:字段值的重复率过高会导致索引失效