Mysql与Ooracle 索引失效场景对比
MySQL 和 Oracle 作为主流关系型数据库,其索引失效的场景既有共性,也因底层优化器、索引类型支持等差异存在不同。以下从常见索引失效场景对比两者的表现及原因:
一、索引列上使用函数 / 表达式
共性:若直接在索引列上使用函数或表达式(如
SUBSTR(name, 1, 3)
、age + 1
),优化器通常无法利用索引,导致失效。- 例:
WHERE SUBSTR(name, 1, 3) = 'abc'
(name
为索引列),两者均可能失效。
- 例:
差异:
- MySQL:在 8.0 版本前不支持 “函数索引”,此类场景必然失效;8.0 后支持函数索引(需显式创建,如
CREATE INDEX idx_func ON t (SUBSTR(name, 1, 3))
),创建后可避免失效。 - Oracle:原生支持 “函数索引”(如
CREATE INDEX idx_func ON t (SUBSTR(name, 1, 3))
),若查询中的函数与索引定义一致,可正常使用索引,否则失效。
- MySQL:在 8.0 版本前不支持 “函数索引”,此类场景必然失效;8.0 后支持函数索引(需显式创建,如
二、OR 连接的条件中存在无索引列
共性:若
OR
连接的多个条件中,存在某列未建索引,优化器可能放弃使用索引(因需同时扫描索引和非索引列,效率可能低于全表扫描)。差异:
- MySQL:对
OR
的处理较严格。即使OR
两边的列都有索引,也可能因优化器判断成本较高而失效(尤其当索引选择性低时)。例如:WHERE age = 20 OR name = 'abc'
(两列均有索引),可能仍走全表扫描。 - Oracle:优化器对
OR
的兼容性更好。若OR
两边的列均有索引,通常会使用索引合并(Index Merge)策略,避免全表扫描。
- MySQL:对
三、否定操作符(!=、<>、NOT IN、IS NOT NULL)
共性:此类操作符可能导致索引失效,因优化器认为扫描范围较大,全表扫描更高效。
差异:
- MySQL:
!=
、NOT IN
、IS NOT NULL
几乎必然导致索引失效(仅当索引列值分布极不均匀时可能例外)。例如:WHERE age != 20
(age
有索引),通常走全表扫描。 - Oracle:处理更灵活。若索引列值稀疏(如大部分为
NULL
,查询IS NOT NULL
),或NOT IN
的范围极小,可能仍使用索引(但效率较低)。
- MySQL:
四、隐式类型转换
- 共性:当索引列类型与查询条件值类型不匹配时,数据库会自动进行类型转换(如字符串列
name
用数字123
查询),导致索引失效。- 例:
WHERE name = 123
(name
为VARCHAR
类型),两者均会失效(因转换为WHERE CAST(name AS UNSIGNED) = 123
,等价于函数操作)。
- 例:
五、模糊查询(LIKE)
共性:以
%
开头的模糊查询(如LIKE '%abc'
),索引通常失效(因无法通过索引前缀定位);以常量开头的查询(如LIKE 'abc%'
),可能使用索引。差异:
- MySQL:
LIKE 'abc%'
仅当索引列是字符串类型且无其他复杂条件时,才会使用索引;若结合其他条件(如AND age > 20
),可能失效。 - Oracle:
LIKE 'abc%'
对 B 树索引的支持更稳定,即使结合其他简单条件,也更可能使用索引(优化器对范围扫描的判断更灵活)。
- MySQL:
六、联合索引违反 “最左前缀原则”
共性:联合索引(如
(a, b, c)
)需满足 “最左前缀”(查询条件包含a
,或a + b
,或a + b + c
),否则失效。- 例:联合索引
(a, b)
,查询WHERE b = 10
,两者均失效。
- 例:联合索引
差异:
- MySQL:若联合索引中左侧列有 “范围查询”(如
a > 10
),则右侧列的索引失效(如WHERE a > 10 AND b = 20
,仅a
的索引有效,b
失效)。 - Oracle:优化器可能对范围查询后的列进行 “跳跃扫描”(Index Skip Scan),尤其当左侧列的基数(不同值数量)较小时(如
a
只有 2 个值),即使a
用范围查询,b
仍可能使用索引。
- MySQL:若联合索引中左侧列有 “范围查询”(如
七、数据量极小或索引选择性低
共性:当表数据量极小(如 <1000 行),或索引列选择性极低(如性别列,只有 “男 / 女”),优化器会认为全表扫描比索引扫描更快,主动忽略索引。
差异:
- MySQL:对 “小表” 的判断更激进,即使表有几万行,若索引选择性低(如重复值占比 > 50%),也可能放弃索引。
- Oracle:优化器对索引选择性的判断更精细,会结合统计信息(如直方图)评估成本,选择性略低时仍可能使用索引。
总结:核心差异点
场景 | MySQL 特点 | Oracle 特点 |
---|---|---|
函数索引支持 | 8.0 后支持,需显式创建 | 原生支持,可直接适配查询中的函数 |
OR 条件处理 | 严格,易失效,索引合并较少 | 灵活,索引合并较常见 |
否定操作符 | 几乎必然失效 | 部分场景(如稀疏数据)可能使用索引 |
联合索引范围查询 | 范围后列索引失效 | 可能支持跳跃扫描,范围后列仍可用索引 |
实际开发中,需结合数据库类型、版本及执行计划(EXPLAIN
/EXPLAIN PLAN
)判断索引是否生效,避免依赖经验主义。