模糊查询%在最前面,能否或者怎么使用索引

本文探讨了SQL中模糊查询(like语句)与索引使用的复杂关系,特别是当查询字符串以通配符%开头时的情况。文章详细介绍了如何通过反转函数和建立相应的索引,使查询效率得到提升,避免全表扫描。同时,分析了在不同场景下,如仅选择索引字段或主键,以及where条件包含主键时,索引的有效利用。

前言

众所周知,在索引时,如果模糊查询的%置于最前面,索引会失效。但是在%前置时,什么情况下会使用到索引?

补充

like %keyword 索引失效,使用全表扫描。但可以通过翻转函数+like前模糊查询+建立翻转函数索引=走翻转函数索引,不走全表扫描。
like keyword% 索引有效。
like %keyword% 索引失效,也无法使用反向索引。

解决

方式一

反转模糊查询的字段,但是注意,对于"%keywork%"的索引,此方法是无效的。

select * from company where companyName like '%江南皮革长';

我们可以改造为:

select * from company where reverse(companyName) like reverse('%江南皮革长');

方式二

首先我们有TEST_USER表:

CREATE TABLE `USER` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `NAME` varchar(64) DEFAULT NULL COMMENT '名字',
  `MOBILE` varchar(11) DEFAULT NULL COMMENT '手机号',
  PRIMARY KEY (`ID`),
  KEY `INDEX_MOBILE` (`MOBILE`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='测试的用户表';

1.只查询索引
EXPLAIN SELECT
	MOBILE
FROM
	USER
WHERE
	MOBILELIKE '%151'

图片.png
Extra:Using index. (走索引)

2.查索引字段和主键
EXPLAIN SELECT
	ID,MOBILE
FROM
	USER
WHERE
	MOBILE LIKE '%151'

图片.png

Extra:Using index. (走索引)

3.查非索引字段
EXPLAIN SELECT
	MOBILE,NAME
FROM
	USER
WHERE
	MOBILE LIKE '%151'

图片.png
Extra:Using where. (不走索引)

4.where后面多条件
4.1where后跟普通条件
EXPLAIN SELECT
	MOBILE
FROM
	USER
WHERE
	NAME = '江南皮革厂'
AND MOBILE LIKE '%151'

图片.png
Extra:Using where. (不走索引)

4.2where后跟主键
EXPLAIN SELECT
	MOBILE
FROM
	USER
WHERE
	ID >1
AND MOBILE LIKE '%151'

图片.png
Extra:Using index. (走索引)

总结

like查询百分号前置,并不是100%不会走索引。
如果只select索引字段,或者select索引字段和主键,也会走索引的。
如果where条件中有主键时,走索引。

一句话:在select和where中存在除了索引和主键外的其他条件或字段时,不走索引。

个人博客
腾讯云社区
掘金
优快云
简书
GitHub
码云
OSCHINA
Segmentfault
公众号:wx.jpg

<think>嗯,用户问的是为什么在Oracle中使用模糊查询(比如使用%%的LIKE语句)后,加上索引会让查询速度明显加快。这个问题看起来有点矛盾,因为通常模糊查询,特别是导通配符的情况,比如'%abc',索引可能不会被使用。但用户说加了索引后确实变快了,所以需要仔细分析可能的情况。 首先,我需要确认用户的具体使用场景。用户提到的是双百分号,也就是类似'%value%'的查询,这种情况下,通常Oracle的B-tree索引不会被使用,因为索引是建立在字段的前面部分,而后都有通配符的话,索引可能无法有效定位数据。但用户说加上索引后速度变快,可能是什么原因呢? 可能的情况有几个: 1. 用户的数据分布特殊,比如虽然用了后通配符,但实际匹配的数据量很小,或者Oracle的优化器选择了索引跳跃扫描(index skip scan),特别是当索引导列具有较低的可选性时,可能跳过某些部分来快速定位数据。 2. 用户创建的索引类型可能不是普通的B-tree索引,比如可能是函数索引,比如将字段转换为大写或使用反转函数,这样即使有通配符也能利用索引。例如,使用reverse函数创建反转索引,查询时用LIKE '%abc',但实际存储是反转后的值,这样可以利用索引。 3. 用户可能使用的是Oracle的Text索引或者其他类型的全文检索索引,这类索引专门处理文本搜索,包括模糊查询,所以即使有通配符也能有效使用。 4. 还有一种可能是,用户的数据量很大,但索引的选择性很高,即使使用索引扫描,由于索引比表小,速度也会更快。或者索引覆盖了查询所需的列,避免了回表操作,从而提升速度。 接下来需要考虑如何验证这些可能性。比如,用户是否使用了函数索引或者查询的条件是否有其他部分可以利用索引。例如,如果查询中除了LIKE还有其他条件,而这些条件可以用到索引,那么整体查询速度提升可能归功于这些条件,而LIKE部分可能依然全扫描,但其他条件过滤了大部分数据。 另外,用户可能误解了索引的应用情况。比如,如果查询是'value%',也就是后导通配符,这时候普通B-tree索引是有效的,但如果是'%value%'或'%value',则可能不生效。如果用户实际使用的是后导通配符,而提问时写错了,那么索引生效是正常的,需要进一步确认用户的实际查询模式。 还需要考虑Oracle的版本特性,比如在较新的版本中,是否引入了新的索引类型或优化策略,使得某些情况下的模糊查询可以利用索引。例如,Oracle 12c引入了In-Memory列存储,或者使用其他优化手段。 后,可能需要查看执行计划,确认索引是否真的被使用。用户可能通过执行计划发现索引使用,从而得出加速的结论,但实际上可能索引并没有直接用于LIKE条件,而是其他部分。这时候需要具体分析执行计划,看索引是如何被利用的。 总结下来,用户的情况可能有多种原因导致索引加速了模糊查询,需要结合具体情况分析,比如索引类型、查询条件、数据分布、Oracle的优化器策略等。需要逐步排查这些可能性,给出合理的解释。</think>在 Oracle 中使用模糊查询(如 `LIKE '%value%'`)时,**加上索引后速度明显加快**可能看似违反直觉,因为通常认为模糊查询(尤其是导通配符 `%`)无法有效利用索引。但实际上,**某些特定场景下索引确实会显著提升性能**。以下是具体原因和深度解析: --- ### **1. 索引类型是关键:普通 B-Tree 索引 vs. 函数索引** - **普通 B-Tree 索引** 如果直接对字段创建普通 B-Tree 索引(如 `CREATE INDEX idx_name ON table(column)`),以下情况可能无法利用索引: ```sql SELECT * FROM table WHERE column LIKE '%abc%'; -- 导通配符,索引通常失效 ``` 因为 B-Tree 索引基于字段的**完整值有序存储**,无法定位中间或结尾的片段。 - **函数索引(Function-Based Index)** 如果创建的是**函数索引**,例如基于字段反转(reverse)或大小写转换的索引,则可以绕过导通配符的限制: ```sql -- 创建反转函数索引 CREATE INDEX idx_reverse ON table(REVERSE(column)); -- 查询时使用反转后的值 SELECT * FROM table WHERE REVERSE(column) LIKE REVERSE('%abc'); -- 实际等价于 column LIKE 'abc%' ``` 此时,模糊查询 `LIKE '%abc'`(注意结尾匹配)会转换为 `REVERSE(column) LIKE 'cba%'`,从而利用索引。 --- ### **2. 索引覆盖(Index-Only Scan)** 如果索引**覆盖了查询所需的列**(即查询仅需要索引中的字段),即使模糊查询需要全索引扫描,也可能比全表扫描更快: ```sql -- 示例:索引覆盖查询字段 CREATE INDEX idx_covering ON table(column, id); -- 包含其他查询字段 -- 查询仅需索引中的字段 SELECT column, id FROM table WHERE column LIKE '%abc%'; ``` 在这种情况下,Oracle 可能直接扫描索引(无需回表),而索引数据量通常远小于全表,因此速度更快。 --- ### **3. 数据分布与索引跳跃扫描(Index Skip Scan)** - **高选择性数据** 如果模糊查询的条件在实际数据中匹配的行数极少(例如 `LIKE '%unique_value%'`),优化器可能选择通过索引快速定位少量数据,避免全表扫描。 - **索引跳跃扫描** 对于复合索引(如 `(gender, column)`),即使模糊查询仅涉及 `column` 字段,Oracle 可能通过跳跃扫描(Skip Scan)依次遍历索引导列(如 `gender` 的每个值),再在子范围内扫描 `column`,从而加速查询。 --- ### **4. Oracle 优化器的特殊处理** 在某些情况下,Oracle 优化器会根据统计信息、系统负载等因素,选择**全索引扫描(Full Index Scan)**而非全表扫描: - **索引数据更紧凑**:索引块中存储的字段值通常比表数据块更集中,I/O 效率更高。 - **缓存利用率更高**:索引可能已被缓存(Buffer Cache),而表数据未缓存。 --- ### **5. 其他优化技术** - **Oracle Text 全文索引** 如果使用 Oracle Text 创建全文索引,模糊查询(如 `CONTAINS`)会直接利用全文索引,效率远高于 `LIKE`。用户可能误以为是普通索引生效,实则是全文索引的优化。 - **分区索引** 若表已分区且索引按分区设计,模糊查询可能仅在部分分区中执行,减少扫描范围。 --- ### **验证索引是否生效的方法** 通过执行计划确认索引是否被使用: ```sql EXPLAIN PLAN FOR SELECT * FROM table WHERE column LIKE '%abc%'; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY); ``` - 如果执行计划显示 `INDEX FULL SCAN` 或 `INDEX SKIP SCAN`,说明索引使用。 - 如果显示 `TABLE ACCESS FULL`,则索引未生效。 --- ### **总结:为什么你的场景中索引有效?** 根据你的描述,可能符合以下情况之一: 1. **使用了函数索引**(如反转索引),间接绕过导通配符限制。 2. **索引覆盖查询字段**,避免回表操作。 3. **数据分布特殊**(如匹配行极少),优化器选择索引扫描。 4. **复合索引的跳跃扫描**生效。 建议通过执行计划进一步确认索引的实际使用方式。若需优化模糊查询,可优先考虑函数索引或全文索引技术。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值