下面是针对oracle 9.2.0.7运行的简单查询。参数来自为旧Boreland驱动程序设计的应用程序。 由于以下查询需要运行超过1小时,因此应用程序存在性能问题。在此之前,数据较少,但数年后数据增长。 这些表具有所有必需的索引,但索引生效了哪些准确值,否则它将执行全表扫描。 如何提高查询的性能我想强制查询使用index.Below我发布了所有必需的信息。请帮助 下面我也有解释计划
SELECT V.*,W.FIRSTNAME || ' ' || W.LASTNAME as personname,
S.LOGINID as SUPERVISOR,
W.COMMROOMID
FROM VOILOG V,LLSWORKER W,LLSWORKER S
WHERE V.INTLLSID = W.LLSID(+) AND W.SUPERVISORID = S.LLSID(+)
AND TRUNC(V.ENTRYDATE) BETWEEN '01-JAN-15' AND '04-MAR-15'
AND W.COMMROOMID like '%9999%'
AND V.VOISUBCATID like '%'
AND S.LOGINID like '%'
AND V.ENTEREDBYLLSID like '%'
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 155 | 22785 | 1101 |
|* 1 | FILTER | | | | |
|* 2 | HASH JOIN | | 155 | 22785 | 1101 |
|* 3 | HASH JOIN | | 162 | 22680 | 1043 |
|* 4 | TABLE ACCESS FULL| VOILOG | 162 | 17496 | 985 |
|* 5 | TABLE ACCESS FULL| LLSWORKER | 1551 | 49632 | 57 |
|* 6 | TABLE ACCESS FULL | LLSWORKER | 1862 | 13034 | 57 |
--------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_DATE('01-JAN-15')<=TO_DATE('04-MAR-15'))
2 - access("W"."SUPERVISORID"="S"."LLSID")
3 - access("V"."INTLLSID"="W"."LLSID")
4 - filter(TRUNC("V"."ENTRYDATE")>='01-JAN-15' AND
TRUNC("V"."ENTRYDATE")<='04-MAR-15' AND
"V"."VOISUBCATID" LIKE '%'
AND TO_CHAR("V"."ENTEREDBYLLSID") LIKE '%')
5 - filter(TO_CHAR("W"."COMMROOMID") LIKE '%9999%')
6 - filter("S"."LOGINID" LIKE '%')
但是当我的查询具有如下所示的确切值时
SELECT V.*,W.FIRSTNAME || ' ' || W.LASTNAME as personname,
S.LOGINID as SUPERVISOR,
W.COMMROOMID
FROM VOILOG V,LLSWORKER W,LLSWORKER S
WHERE V.INTLLSID = W.LLSID(+) AND W.SUPERVISORID = S.LLSID(+)
AND TRUNC(V.ENTRYDATE) BETWEEN '01-JAN-15' AND '04-MAR-15'
AND W.COMMROOMID like '9999'
AND V.VOISUBCATID like '%'
AND S.LOGINID like '%'
AND V.ENTEREDBYLLSID like '%'
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 147 | 239 |
|* 1 | FILTER | | | | |
|* 2 | TABLE ACCESS BY INDEX ROWID | VOILOG | 1 | 108 | 181 |
| 3 | NESTED LOOPS | | 1 | 147 | 239 |
| 4 | NESTED LOOPS | | 1 | 39 | 58 |
|* 5 | TABLE ACCESS FULL | LLSWORKER | 1 | 32 | 57 |
|* 6 | TABLE ACCESS BY INDEX ROWID| LLSWORKER | 1 | 7 | 1 |
|* 7 | INDEX UNIQUE SCAN | XPKLLSWORKER | 1 | | |
|* 8 | INDEX RANGE SCAN | XIEINTLLSID1 | 198 | | 2 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_DATE('01-JAN-15')<=TO_DATE('04-MAR-15'))
2 - filter(TRUNC("V"."ENTRYDATE")>='01-JAN-15' AND
TRUNC("V"."ENTRYDATE")<='04-MAR-15' AND "V"."VOISUBCATID" LIKE '%'AND
TO_CHAR("V"."ENTEREDBYLLSID") LIKE '%')
5 - filter(TO_CHAR("W"."COMMROOMID") LIKE '9999')
6 - filter("S"."LOGINID" LIKE '%')
7 - access("W"."SUPERVISORID"="S"."LLSID")
8 - access("V"."INTLLSID"="W"."LLSID")
答案 0 :(得分:1)
夫妻俩。
SELECT V.*,W.FIRSTNAME || ' ' || W.LASTNAME as personname,
S.LOGINID as SUPERVISOR,
W.COMMROOMID
FROM VOILOG V,LLSWORKER W,LLSWORKER S
WHERE V.INTLLSID = W.LLSID(+) AND W.SUPERVISORID = S.LLSID(+)
AND TRUNC(V.ENTRYDATE) BETWEEN '01-JAN-15' AND '04-MAR-15'
AND W.COMMROOMID like '%9999%'
AND V.VOISUBCATID like '%'
AND S.LOGINID like '%'
AND V.ENTEREDBYLLSID like '%'
其一,如果V.ENTRYDATE
上有索引,则使用TRUNC()
将导致Oracle不使用该索引。您想按如下方式重写该条件:
WHERE v.entrydate >= date'2015-01-01'
AND v.entrydate < date'2015-03-04' + 1
我们在<
条件中使用AND
的原因是排除v.entrydate
等于2015-03-05
(没有时间部分)的情况。 (注意:我正在使用上面的ANSI日期文字,这在Oracle 9中受支持...否则您可能会使用TO_DATE('01-JAN-15', 'MM-DD-RR')
来避免隐式转换为日期。)
二,您正在使用外连接,即使它们永远不会被使用,因为外部连接到VOILOG
的表上的条件:
AND w.commroomid LIKE '%9999%'
...
AND s.loginid LIKE '%'
换句话说,没有理由在这里使用外连接,您可以使用内连接。或者,您可以明确处理NULL
和w.commroomid
上的s.loginid
条件:
AND NVL(w.commroomid, '0') LIKE '%9999%'
...
AND NVL(s.loginid, '0') LIKE '%'
另一种可以处理的方法是将这些条件包含在显式ANSI LEFT JOIN
中 - 但这只有在你想要返回NULL
时才会这样:
FROM voilog v LEFT JOIN llsworker w
ON v.intllsid = w.llsid
AND w.commroomid LIKE '%9999%'
三,我不知道w.commroomid
等是否被编入索引,但在LIKE
条件下使用前导通配符意味着索引未被使用。