MySQL 组合IN查询:你的索引为什么罢工了?

MySQL 组合IN查询:你的索引为什么罢工了?

WHERE (a,b) IN ((1,2),(3,4)) 让你的索引躺平,是时候谈谈人生了

🚦 问题现场

周五加班写的优雅查询:

sql 复制代码
SELECT * FROM orders 
WHERE (user_id, status) IN ((1001, 'paid'), (1002, 'shipped'));

结果------全表扫描!索引像周末的你一样彻底躺平 😴

🔍 为什么索引失效?

原因1:MySQL优化器的"近视眼"

MySQL对多列组合IN的优化较弱,可能被拆解为OR条件:

sql 复制代码
-- 实际可能被优化为:
WHERE (user_id = 1001 AND status = 'paid') 
   OR (user_id = 1002 AND status = 'shipped');

导致复合索引(user_id, status)失效

原因2:数据类型"出轨"

sql 复制代码
-- ❌ 字符串漏引号(隐式类型转换)
WHERE (user_id, status) IN ((1001, paid)); -- 应该是'paid'

🛠️ 四大解决方案

方案1:UNION ALL 大法(推荐)

sql 复制代码
SELECT * FROM orders WHERE user_id = 1001 AND status = 'paid'  
UNION ALL  
SELECT * FROM orders WHERE user_id = 1002 AND status = 'shipped';

优点:每条子查询都能命中索引

方案2:临时表JOIN(适合大量组合)

sql 复制代码
CREATE TEMPORARY TABLE temp_conditions (
  user_id INT, 
  status VARCHAR(20)
);
INSERT INTO temp_conditions VALUES 
  (1001, 'paid'), (1002, 'shipped');

SELECT o.* FROM orders o JOIN temp_conditions t  
ON o.user_id = t.user_id AND o.status = t.status;

方案3:强制索引(慎用!)

sql 复制代码
SELECT * FROM orders FORCE INDEX(idx_user_status)
WHERE (user_id, status) IN ((1001, 'paid'), (1002, 'shipped'));

方案4:应用层拆分

java 复制代码
// 伪代码:分批查询再合并
List<Order> queryByPairs(List<Pair<Integer, String>> pairs) {
  return pairs.stream()
    .flatMap(pair -> jdbc.query(
      "SELECT * FROM orders WHERE user_id=? AND status=?", 
      pair.getKey(), pair.getValue()))
    .collect(Collectors.toList());
}

💡 预防措施

  1. 必看执行计划

    sql 复制代码
    EXPLAIN SELECT ...;
    • 警惕type=ALL
    • 关注key列是否使用索引
  2. 复合索引顺序很重要

    sql 复制代码
    ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
  3. 保持类型纯洁性

    sql 复制代码
    -- ✅ 正确姿势
    WHERE (user_id, status) IN ((1001, 'paid'), (1002, 'shipped'))

📢 下期预告

《MySQL索引失效的10种骚操作》

  • 为什么WHERE DATE(create_time) = '2023-01-01'会让索引哭泣?
  • LIKE '%关键字%'的终极解决方案
  • 隐式类型转换的连环坑

互动话题

你遇到过哪些「索引突然摆烂」的灵异事件?

欢迎评论区分享你的「调教索引」秘籍! 💬

友情提示 :周末禁止SELECT * FROM problems🚫)

相关推荐
考虑考虑2 小时前
docker compose V2版本新属性
运维·后端·自动化运维
GreenTea4 小时前
7000 万 QPS、500 PB:OpenAI 如何用一个 Python 存储平台撑住 10 亿用户
后端·架构
Flynt5 小时前
Java 27 升级实测:默认值动得比新特性多,有个老参数会让 JVM 直接起不来
java·jvm·后端
Bs_MoneyMagnet5 小时前
基于springboot+vue的个人健康管理系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·vue3·springboot3·计算机毕业设计
GreenTea5 小时前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
Bs_MoneyMagnet7 小时前
基于springboot+vue的心理咨询预约与随访平台的设计与实现 源码+文档
vue.js·spring boot·后端·spring·毕业设计·旅游·计算机毕业设计
IT_陈寒8 小时前
Vue的响应式更新把我坑惨了,原来问题出在这
前端·人工智能·后端
陌シ未央ゞ9 小时前
基于BM25算法和RRF实现的混合索引(java版)
人工智能·spring boot·后端·算法
第五页的你9 小时前
SpringBoot基础设施配置(Redis序列化,JJWT新版)
后端
吃饱了得干活9 小时前
RabbitMQ 原理解析(下):存储、集群与可靠投递
后端·rabbitmq