我有一个包含与员工相关的所有数据的视图。 它有大约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是一个视图,我无法使用索引。
答案 0 :(得分:1)
虽然你不能在视图上放置索引,但你当然可以在索引表上放置索引。但是,如@JustinCave所述,即使您确实将索引添加到相应的表中,由于使用了LIKE
,此查询仍然不会使用它们。此外,由于UPPER
函数应用于FIRST_NAME
,MIDDLE_NAME
和LAST_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语句,例如,当搜索字符串包含至少三个字母时,您将使用一个完整的表提示,而另一个则使用您将使用的索引提示。
你知道,你想的越多,就越复杂。我建议先尝试并行提示。也许这已经足够快了。