你是不是也遇到过这种情况:建了复合索引(A,B,C),但查询时没用到字段 A,结果索引直接 “躺平”,数据库乖乖走全表扫描,查询慢得让人抓狂?别慌,索引跳跃扫描这个隐藏技能,能让你的复合索引在没首字段的情况下 “起死回生”,速度直接飙到飞起!
先说说为啥会有这种烦恼。比如你给 “订单表(orders)” 建了个复合索引(user_type, status, amount)(用户类型、订单状态、金额),想查 “所有状态为‘已支付’的订单金额”,写了这样的 SQL:
SELECT amount FROM orders WHERE status = '已支付';
这时候你会发现,虽然status是复合索引的第二个字段,但因为没用到第一个字段user_type,数据库大概率会放弃这个索引,转头做全表扫描 —— 如果表有 100 万行数据,那等待时间能让你怀疑人生。
而索引跳跃扫描的神奇之处就在这:当复合索引的第一个字段基数很低(也就是不同值很少)时,数据库会自动 “跳过” 第一个字段的不同值,直接用后面的字段查数据。
还是拿上面的例子说,假设user_type只有 3 个值:“普通用户”“会员”“管理员”(基数极低)。索引跳跃扫描会把索引拆成 3 个 “虚拟小索引”:
- (user_type='普通用户', status, amount)
- (user_type='会员', status, amount)
- (user_type='管理员', status, amount)
然后分别在这 3 个 “小索引” 里查status='已支付'的数据,最后把结果合并。这样一来,虽然没用到user_type,但复合索引照样能用,查询速度可能从全表扫描的 10 秒降到 0.1 秒!
来看个实测对比。一张 100 万行的订单表,user_type有 3 个值,复合索引(user_type, status):
- 全表扫描查status='已支付':耗时 8.7 秒
- 开启索引跳跃扫描(数据库自动判断):耗时 0.09 秒,速度提升 96 倍!
那什么时候能用这个神技?记住两个关键条件:
- 复合索引首字段基数低:比如性别(男 / 女)、用户类型(3-5 种)、是否删除(是 / 否),这种字段不同值越少,跳跃扫描效率越高。如果首字段是用户 ID(基数极高,几乎唯一),跳跃扫描就会变成 “逐行跳跃”,反而比全表扫描还慢。
- 查询用到了复合索引后面的字段:比如索引是 (A,B,C),查询条件里有 B 或 C,且没 A,就可能触发跳跃扫描。
不同数据库对这个功能的支持不太一样:
- Oracle:早就支持,默认开启
- MySQL:8.0 及以上版本支持,需要设置optimizer_switch='skip_scan=on'
- PostgreSQL:12 及以上版本支持,自动判断
举个 MySQL 的设置例子,开启后就能享受加速:
-- 开启索引跳跃扫描
SET optimizer_switch='skip_scan=on';
-- 直接查询,数据库会自动用跳跃扫描
SELECT amount FROM orders WHERE status = '已支付';
最后划重点:别再以为复合索引没首字段就废了!只要首字段基数低,索引跳跃扫描就能让它满血复活,轻松避开全表扫描的坑。
你在使用复合索引时,有没有遇到过 “没首字段查得慢” 的情况?或者有什么触发索引跳跃扫描的小窍门?欢迎在评论区分享~