优化oracle中的字符串搜索

时间:2013-09-04 19:48:27

标签: plsql oracle11g query-tuning

我有一个包含与员工相关的所有数据的视图。 它有大约350k的记录。 我必须进行名称搜索功能。 这将检索与输入的关键字匹配的所有数据。

查询性能非常慢,需要15-20秒才能检索数据。 成本-15000

我的查询:

 SELECT            H.PERSON_ID,
                   B.EMPLOYEE_ID,
                   INITCAP(B.FIRST_NAME) EMP_FNAME,
                   INITCAP(B.MIDDLE_NAME) EMP_MNAME,
                   INITCAP(B.LAST_NAME) EMP_LNAME,
                   B.EMPLOYEE_TYPE PERSON_DESC,
                   B.EMPLOYMENT_STATUS STATUS_TYPE,
                   EA.BASE_BRANCH

              FROM EMPLOYEE_BASIC_DTLS   B,
                   EMP_ASSIGNMENT_DTLS_MV EA,
                   EMPLOYEE_HIS_DEPNDENT_TBL  H
             WHERE B.PERSON_ID = EA.PERSON_ID
               AND B.PERSON_ID = H.PERSON_ID
               AND ((UPPER(B.FIRST_NAME) LIKE
                   ('%' || V_SEARCH_PARAM1 || '%')) OR
                   (UPPER(B.MIDDLE_NAME) LIKE
                   ('%' || V_SEARCH_PARAM1 || '%')) OR
                   (UPPER(B.LAST_NAME) LIKE
                   ('%' || V_SEARCH_PARAM1 || '%')))
               AND TRUNC(SYSDATE) BETWEEN EA.EFFECTIVE_START_DATE AND
                   EA.EFFECTIVE_END_DATE
               AND UPPER(H.RELATIONSHIP_CODE) = 'A';

由于EMPLOYEE_BASIC_DTLS是一个视图,我无法使用索引。

2 个答案:

答案 0 :(得分:1)

虽然你不能在视图上放置索引,但你当然可以在索引表上放置索引。但是,如@JustinCave所述,即使您确实将索引添加到相应的表中,由于使用了LIKE,此查询仍然不会使用它们。此外,由于UPPER函数应用于FIRST_NAMEMIDDLE_NAMELAST_NAME列,因此您需要将索引定义为基于函数的索引。例如,如果EMPLOYEE_BASIC_TABLE视图访问的“真实”表格被称为EMPLOYEES,您可以在FIRST_NAME列上定义基于函数的索引

CREATE INDEX EMPLOYEES_UPPER_FIRST_NAME ON EMPLOYEES (UPPER(FIRST_NAME));

我建议你考虑是否真的需要LIKE比较,因为努力提高性能将会很困难。

如果您想调查Oracle Text索引,可以找到文档here。我认为你会发现它更适合于记录或记录片段索引,但也许它会给你一些想法。

分享并享受。

答案 1 :(得分:1)

由于可能会查找任何名称或名称的任何部分,因此无法创建包含要预先搜索的值的索引。所以这对你没有帮助。 Oracle将进行全表扫描以检查每个字符串是否匹配。

你可以做的是加快扫描速度。

例如,您可以通过/ * + parallel(EMPLOYEE_BASIC_TABLE,4)* /并行化来加速全表扫描。 (这是我的建议。)

或者你可以通过每列有一个索引来避免全表扫描,因为我们知道有许多重复使用的名称,因此每个名称只扫描一次。然后你会像Bob Jarvis建议的那样在底层表上使用基于函数的键,因为你在任何名字上都使用了upper函数。最快的是综合指数:

create bitmap index idx_name_search on EMPLOYEE_BASIC_TABLE (upper(first_name || '|' || middle_name || '|' || last_name))

所以只有一个索引要查找。 (当然,你必须在你的查询中使用这个表达式:WHERE upper(first_name ||'|'|| middle_name ||'|'|| last_name),如'%JOHN%'。)但是,你仍然我知道会提前搜索什么,并且'%JOHN%'可能只影响2%的表数据,'%E%'可能会影响80%。优化器永远不会知道。您至少可以猜测并且必须使用不同的select语句,例如,当搜索字符串包含至少三个字母时,您将使用一个完整的表提示,而另一个则使用您将使用的索引提示。

你知道,你想的越多,就越复杂。我建议先尝试并行提示。也许这已经足够快了。