场景为:

table_a 是一个超过250万行的表

CREATE TABLE `table_a` (
  `id` varchar(32) NOT NULL COMMENT 'id',
  `user_id` int NOT NULL DEFAULT '0' COMMENT '用户id',
  `status` tinyint NOT NULL DEFAULT '0',
  ...
  ...
  `create_time` '创建时间',
  `update_time` '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_user_id_status` (`user_id`,`status`) USING BTREE,
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='';

问题:

- 1,2,3只表示数量 真实数据非有序或连续
select * from table_a where user_id in(1,2,3, ... ,700) and status in(1,2);

查询需要大几十秒

问题分析:

使用explain 解析sql查询计划,发现mysql优化器未选择索引,idx_user_id_status索引失效,原因是条件user_id in的数据量大于700个,全表扫描导致查询时间长。

解决方案:

1.数据拆分

将in查询的数据拆分,将700条分为7条查询sql 每条只in100以内。
优点:避开优化器该机制,好理解
缺点:实现复杂,需要额外写代码组装sql。

2.使用虚拟表

将700个userId放入虚拟表中 然后使用连表查询,这样也会走索引查询时间为毫秒级。

create table tmp_user_id(user_id) as select * from (1,2,3,...700) ;
select * from table_a t1, tmp_user_id t2 where t1.user_id = t2.user_id and status in(1,2);

优点:原理简单,不需要额外写代码
缺点:sql相对复杂,需要建立虚拟表,及销毁该虚拟表。

3.强制索引(推荐)

使用强制索引 ,查询中增加关键字**FORCE INDEX (idx_user_id_status)**指定mysql的优化选择器强制使用该索引,使用索引后查询时间为毫秒级

 select * from table_a FORCE INDEX (idx_user_id_status) where user_id in(1,2,3,...700) and status in(1,2);

优点:实现简单
缺点:强制该查询指定了索引,只能用于特定的某个方法

4.优化mysql配置

优先选择多索引而不是单索引

Logo

永洪科技,致力于打造全球领先的数据技术厂商,具备从数据应用方案咨询、BI、AIGC智能分析、数字孪生、数据资产、数据治理、数据实施的端到端大数据价值服务能力。

更多推荐