采用全文索引解决模糊查询速度慢的问题

本文详细介绍了如何通过全文索引解决Oracle数据库中模糊查询速度慢的问题,包括创建全文检索索引的步骤、使用方法、同步与优化策略,以及通过Job任务实现定期同步和优化,显著提升数十万用户数据中地址模糊查询的速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

众所周知,使用 like 进行模糊查询速度极差,包括 like 'AAA%' ,like '%AAA',like '%AAA%',like '%A%A%'以及采用“_”进行单字符匹配的那些模糊查询。网上有很多文章讲到如何提高like查询,提到 like 'AAA%'能够使用到索引,而like '%AAA' ,使用创建反向函数的索引来提高查询效率。但一般情况下,是无法约定客户端采用哪种like查询,难道说把所有的这些情况都进行if判断吗?

为这个事情脑袋疼了无数次。最近,一客户“无理”要求对用户地址模糊查询速度太慢。在数十万的用户记录下查询,要求5秒之内必须查询到记录。

想破脑袋还是找不到方法。有同事找了本Lucene的书给我看,说是能解决。翻来覆去的看了2,3遍,始终想不出这玩意儿怎么用。

突然想到oracle也有全文索引一说,以前只是别人提起过这个词。与网上朋友一聊,说是似乎可以解决,但他忘了怎么用了。

半夜12点,赶紧爬起来,到google上查资料。还真有两下子,研究了几个小时,有所获。第二天白天没时间研究,晚上继续,最终把全文索引搞定,解决了模糊查询速度慢的问题,在数十万条用户数据中, 对用户地址进行模糊查询速度在2秒以内就能够查到。

-------------------------------------------------------------------------

以下是创建全文索引的方法(网上有文章提到使用图形化界面,我用图形化界面创建全文索引,创建了一个晚上,第二天起床居然还没完。但用SQL命令15分钟左右就搞定):

对cmng_custominfo 表中的address字段做全文检索:
1,在oracle9201中需要创建一个分词的东西:

BEGIN
ctx_ddl.create_preference ('SMS_ADDRESS_LEXER', 'CHINESE_LEXER');
--ctx_ddl.create_preference ('my_lexer', 'chinese_vgram_lexer'); 不用
end;

2,创建全文检索:

CREATE INDEX INX_CUSTOMINFO_ADDR_DOCS ON cmng_custominfo(address) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('LEXER SMS_ADDRESS_LEXER');

3,查询时候,使用:

select * from cmng_custominfo where contains (address, '金色新城')>1;

自己测试,发现select * from cmng_custominfo where contains (address, '%金色新城%')>1;才能实现模糊查询,并且使用了索引,数据库版本为oracle9.0.1.1.1

4,需要定期进行同步和优化:
同步:根据新增记录的文本内容更新全文搜索的索引。

begin
ctx_ddl.sync_index('INX_CUSTOMINFO_ADDR_DOCS');
end;

优化:根据被删除记录清除全文搜索索引中的垃圾

begin
ctx_ddl.optimize_index('INX_CUSTOMINFO_ADDR_DOCS', 'FAST');
end;

5,采用job做步骤4中的工作:

1)该功能需要利用oracle的JOB功能来完成
因为oracle9I默认不启用JOB功能,所以首先需要增加ORACLE数据库实例的JOB配置参数:
job_queue_processes=5
重新启动oracle数据库服务和listener服务。

2)同步 和 优化
--同步 sync:
variable jobno number;
BEGIN
DBMS_JOB.SUBMIT(:jobno,'ctx_ddl.sync_index(''INX_CUSTOMINFO_ADDR_DOCS'');', SYSDATE, 'SYSDATE + (1/24/4)');
 commit;
END;

--优化
variable jobno number;
begin
 DBMS_JOB.SUBMIT(:jobno,'ctx_ddl.optimize_index(''INX_CUSTOMINFO_ADDR_DOCS'',''FULL'');', SYSDATE, 'SYSDATE + 1');
 commit;
END;

其中, 第一个job的SYSDATE + (1/24/4)是指每隔15分钟同步一次,第二个job的SYSDATE + 1是每隔1天做一次全优化。具体的时间间隔,可以根据应用的需要而定

6,索引重建
重建索引会删除原来的索引,重新生成索引,需要较长的时间。
重建索引语法如下:
ALTER INDEX INX_CUSTOMINFO_ADDR_DOCS REBUILD;

据网上一些用家的体会,oracle重建索引的速度也是比较快的,有一用家这样描述:

Oracle 的全文检索建立和维护索引要比ms sql server都要快得多,笔者的65万记录的一个表建立索引只需要20分钟,同步一次只需要1分钟。
因此,也可以考虑用job的办法定期重建索引。

参考资料:
1,http://blog.youkuaiyun.com/yurenjia/archive/2007/04/08/1556306.aspx
2,http://topic.youkuaiyun.com/u/20080117/23/34004f4a-4989-47ef-8764-0b7e3bf737a7.html
3,http://tenwe.com/tech/database/oracle/200702/content_561_4.shtml
4,http://www.knowsky.com/389357.html
5,http://yangtingkun.itpub.net/post/468/195520
6,http://bbs.zdnet.com.cn/archiver/tid-120474.html
7,http://bbs.违规广告.com/archiver/tid-26270.html
8,http://oracle.**.com/exploiture/720104_3.html
9,http://www.33kuai.cn/html/shujuku/20080126/5314_2.html
10,http://www.xrss.cn/Dev/DataBase/20084218963.Html

### MySQL 素引失效原因 索引在特定情况下可能会失效,这会对查询性能造成负面影响。以下是几种常见的索引失效情形: - **条件表达式中使用了函数**:如果在 `WHERE` 子句中的列上应用了任何函数,则即使存在针对该列的索引也不会被利用[^3]。 - **使用 "不等于" (`<>`, `!=`) 操作符**:当查询条件涉及非等值比较时(例如 `<>` 或者 `!=`),MySQL 可能不会有效地使用索引来加速查找过程。 - **列类型不匹配**:如果表定义里的字段类型与查询条件里提供的值之间存在隐式转换需求,那么也可能导致索引无法正常工作。 - **LIKE 进行模糊匹配**:特别是以通配符开头 `%abc%` 的模式匹配会使索引变得无用;因为在这种情况下数据库引擎不得不扫描整个表来找到符合条件的数据项。 - **数据量过小**:对于非常小规模的数据集来说,创建并维护额外结构所带来的开销可能超过了直接全表扫面的成本,在这种环境下索引也难以发挥其优势。 - **范围查询后的精确匹配**:在一个复合索引 `(age, name)` 上执行类似 `age = 18 AND name > 'xx'` 的查询时,虽然可以利用到第一个键 `age` 的索引部分来进行筛选,但对于第二个键 `name` 则由于进行了范围检索而失去了后续更进一步精确定位的能力[^2]。 ### 解决方案 为了应对上述提到的各种可能导致索引失效的情况,可采取如下措施: #### 针对函数调用问题 尽可能避免在查询条件中对索引列施加计算或变换处理。可以通过预先存储经过相同运算的结果作为新属性的方式绕过此障碍,从而允许这些预处理过的数值参与高效的索引访问路径。 #### 处理非等价关系操作 考虑重构 SQL 表达式以便能够更好地适应现有索引策略。比如尝试拆分复杂的选择标准成多个简单子句组合而成的形式,或是引入辅助索引来覆盖更多类型的过滤逻辑。 #### 类型一致性保障 确保应用程序层面上所提供的参数格式严格遵循底层持久化对象的设计规格说明书中所规定的预期输入样式,减少不必要的自动转型动作发生频率。 #### LIKE 使用优化建议 尽量让前缀固定的部分越长越好,并且只把不确定因素放在字符串结尾处,即采用形如 `'prefix%'` 而不是 `'%suffix'` 的写法。另外还可以借助全文搜索引擎技术实现更加灵活多样的文本检索功能而不必依赖传统 B-tree 结构下的有限支持程度。 #### 数据分布考量 评估实际业务场景下是否真的有必要为那些记录数极少的小表格建立专门用于提升读取速度的附加设施——有时候简单的顺序遍历反而更快捷有效得多! #### 综合运用最左前缀原理 理解并充分利用好 MySQL 中关于联合索引的工作机制,按照查询习惯合理安排各组成要素之间的先后次序,使得尽可能多的实际应用场景都能享受到来自硬件层面带来的增益效果[^1]。 ```sql -- 创建一个适合于频繁使用的查询模式的新索引 CREATE INDEX idx_age_name ON users (age, name); -- 对于经常性的范围查询加上必要的限制条件以提高命中率 SELECT * FROM users WHERE age BETWEEN 18 AND 20 AND name >= 'A'; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值