由于sql查询的性能问题

时间:2015-03-07 19:10:04

标签: sql oracle oracle11g

下面是针对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")

1 个答案:

答案 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 '%'

换句话说,没有理由在这里使用外连接,您可以使用内连接。或者,您可以明确处理NULLw.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条件下使用前导通配符意味着索引未被使用。