2

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

查询性能非常慢,检索数据需要 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 是我不能使用索引的视图。

4

2 回答 2

1

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

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

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

或者您可以通过每列有一个索引来避免全表扫描,因为您知道有许多重复使用的名称,因此每个名称只被扫描一次。然后,您将按照 Bob Jarvis 的建议在基础表上使用基于函数的键,因为您在任何名称上都使用了上层函数。最快的将是一个组合索引:

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) like '%JOHN%'。)但是,你仍然没有'不知道会提前搜索什么,因为 '%JOHN%' 可能只影响 2% 的表数据,'%E%' 可能影响 80%。优化器永远不会知道。您至少可以猜测并且必须使用不同的选择语句,例如,当搜索字符串包含至少三个字母时,您将使用完整的表提示,而在其他情况下,您将使用索引提示。

你看,你越想越复杂。我建议先尝试并行提示。也许这已经足够加快速度了。

于 2013-09-05T12:40:03.170 回答
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 索引,可以在此处找到文档。我想你会发现它更适合文档或文档片段索引,但也许它会给你一些想法。

分享和享受。

于 2013-09-05T01:37:56.017 回答