As David points out, the Oracle version number (for example 9.2.0.4)
is important, as it determines what types of transformations Oracle
may use to help improve the query performance. First, a slight change
in the formatting to make it easier for me to read (you will need to
fix the DECODE statements):
SELECT DISTINCT
AM.ACCNAME,
SUBSTR (TD.VOUNO, 3) VOUNO,
TD.VOUDATE,
TD.TRANTYPE,
CD.CHEQUENO,
CD.CHEQUEDATE,
DECODE (BALTYPE, 'DEBIT', AMOUNT, 0) DEBIT,
DECODE (BALTYPE, 'CREDIT', AMOUNT, 0) CREDIT,
TDD.DOCNO,
TDD.DOCDATE,
TD.REMARK
FROM
TRANDETAILS TD,
CHEQUEDETAILS CD,
ACCMASTER AM,
TRANDOCDETAILS TDD
WHERE
AM.ACCCODE <> :P_BANKACCCODE
AND TD.VOUDATE BETWEEN :ST_DATE AND :END_DATE
AND TD.COMPANYNO = AM.COMPANYNO
AND TD.COMPANYNO = CD.COMPANYNO(+)
AND TD.VOUNO = CD.VOUNO(+)
AND TD.VOUDATE = CD.VOUDATE(+)
AND TD.NU_SERIAL_NO = CD.NU_SERIAL_NO(+)
AND TD.NU_SERIAL_NO = TDD.NU_SERIAL_NO(+)
AND TD.ACCCODE = AM.ACCCODE
AND TD.TRANTYPE IN ('JV', 'BR', 'BP', 'CN', , 'CR', 'CP')
AND NVL (TD.SECFLAG, 'N') = 'Y'
AND TDD.VOUNO(+) = TD.VOUNO
AND TDD.VOUDATE(+) = TD.VOUDATE
AND AM.COMPANYNO = :P_COMPANYNO
AND TDD.COMPANYNO(+) = :P_COMPANYNO
AND TD.COMPANYNO || TD.VOUNO || TO_CHAR (TD.VOUDATE, 'DD-MM-YYYY')
IN
(SELECT
TD2.COMPANYNO || TD2.VOUNO || TO_CHAR (TD2.VOUDATE, 'DD-MM-
YYYY')
FROM
TRANDETAILS TD2
WHERE
TD2.ACCCODE = :P_BANKACCCODE
AND NVL (TD2.SECFLAG, 'N') = 'Y'
AND TD2.COMPANYNO = :P_COMPANYNO)
ORDER BY
3,
2;
In the above, you are concatenating three columns into a single value,
and then trying to determine if the same concatenated value exists in
a table. A DBMS_XPLAN would probably show many, many full table scans
of the TRANSDETAILS table.
If we just list the three columns, and use TRUNC rather than TO_CHAR,
we may be able to take advantage of an index on those columns, and
avoid the CPU overhead of a data type conversion of a DATE column to a
character data type. You could use an EXISTS syntax instead, which
might be more efficient (not shown):
SELECT DISTINCT
AM.ACCNAME,
SUBSTR (TD.VOUNO, 3) VOUNO,
TD.VOUDATE,
TD.TRANTYPE,
CD.CHEQUENO,
CD.CHEQUEDATE,
DECODE (BALTYPE, 'DEBIT', AMOUNT, 0) DEBIT,
DECODE (BALTYPE, 'CREDIT', AMOUNT, 0) CREDIT,
TDD.DOCNO,
TDD.DOCDATE,
TD.REMARK
FROM
TRANDETAILS TD,
CHEQUEDETAILS CD,
ACCMASTER AM,
TRANDOCDETAILS TDD
WHERE
AM.ACCCODE <> :P_BANKACCCODE
AND TD.VOUDATE BETWEEN :ST_DATE AND :END_DATE
AND TD.COMPANYNO = AM.COMPANYNO
AND TD.COMPANYNO = CD.COMPANYNO(+)
AND TD.VOUNO = CD.VOUNO(+)
AND TD.VOUDATE = CD.VOUDATE(+)
AND TD.NU_SERIAL_NO = CD.NU_SERIAL_NO(+)
AND TD.NU_SERIAL_NO = TDD.NU_SERIAL_NO(+)
AND TD.ACCCODE = AM.ACCCODE
AND TD.TRANTYPE IN ('JV', 'BR', 'BP', 'CN', , 'CR', 'CP')
AND NVL (TD.SECFLAG, 'N') = 'Y'
AND TDD.VOUNO(+) = TD.VOUNO
AND TDD.VOUDATE(+) = TD.VOUDATE
AND AM.COMPANYNO = :P_COMPANYNO
AND TDD.COMPANYNO(+) = :P_COMPANYNO
AND (TD.COMPANYNO,TD.VOUNO,TRUNC(TD.VOUDATE)) IN
(SELECT
TD2.COMPANYNO,
TD2.VOUNO,
TRUNC(TD2.VOUDATE)
FROM
TRANDETAILS TD2
WHERE
TD2.ACCCODE = :P_BANKACCCODE
AND NVL (TD2.SECFLAG, 'N') = 'Y'
AND TD2.COMPANYNO = :P_COMPANYNO)
ORDER BY
3,
2;
Let's transform the subquery into an inline view, which will sometimes
help improve performance (usually a very noticeable on Oracle 8i).
Such a transformation may be performed by Oracle automatically:
SELECT DISTINCT
AM.ACCNAME,
SUBSTR (TD.VOUNO, 3) VOUNO,
TD.VOUDATE,
TD.TRANTYPE,
CD.CHEQUENO,
CD.CHEQUEDATE,
DECODE (BALTYPE, 'DEBIT', AMOUNT, 0) DEBIT,
DECODE (BALTYPE, 'CREDIT', AMOUNT, 0) CREDIT,
TDD.DOCNO,
TDD.DOCDATE,
TD.REMARK
FROM
TRANDETAILS TD,
CHEQUEDETAILS CD,
ACCMASTER AM,
TRANDOCDETAILS TDD,
(SELECT DISTINCT
TD2.COMPANYNO,
TD2.VOUNO,
TRUNC(TD2.VOUDATE) VOUDATE
FROM
TRANDETAILS TD2
WHERE
TD2.ACCCODE = :P_BANKACCCODE
AND NVL (TD2.SECFLAG, 'N') = 'Y'
AND TD2.COMPANYNO = :P_COMPANYNO) TD2
WHERE
AM.ACCCODE <> :P_BANKACCCODE
AND TD.VOUDATE BETWEEN :ST_DATE AND :END_DATE
AND TD.COMPANYNO = AM.COMPANYNO
AND TD.COMPANYNO = CD.COMPANYNO(+)
AND TD.VOUNO = CD.VOUNO(+)
AND TD.VOUDATE = CD.VOUDATE(+)
AND TD.NU_SERIAL_NO = CD.NU_SERIAL_NO(+)
AND TD.NU_SERIAL_NO = TDD.NU_SERIAL_NO(+)
AND TD.ACCCODE = AM.ACCCODE
AND TD.TRANTYPE IN ('JV', 'BR', 'BP', 'CN', , 'CR', 'CP')
AND NVL (TD.SECFLAG, 'N') = 'Y'
AND TDD.VOUNO(+) = TD.VOUNO
AND TDD.VOUDATE(+) = TD.VOUDATE
AND AM.COMPANYNO = :P_COMPANYNO
AND TDD.COMPANYNO(+) = :P_COMPANYNO
AND TD.COMPANYNO=TD2.COMPANYNO
AND TD.VOUNO=TD2.VOUNO
AND TRUNC(TD.VOUDATE)=TD2.VOUDATE
ORDER BY
3,
2;
Is it really necessary to reference the TRANDETAILS table twice? Will
the following work?:
SELECT DISTINCT
AM.ACCNAME,
SUBSTR (TD.VOUNO, 3) VOUNO,
TD.VOUDATE,
TD.TRANTYPE,
CD.CHEQUENO,
CD.CHEQUEDATE,
DECODE (BALTYPE, 'DEBIT', AMOUNT, 0) DEBIT,
DECODE (BALTYPE, 'CREDIT', AMOUNT, 0) CREDIT,
TDD.DOCNO,
TDD.DOCDATE,
TD.REMARK
FROM
TRANDETAILS TD,
CHEQUEDETAILS CD,
ACCMASTER AM,
TRANDOCDETAILS TDD
WHERE
AM.ACCCODE <> :P_BANKACCCODE
AND TD.VOUDATE BETWEEN :ST_DATE AND :END_DATE
AND TD.COMPANYNO = AM.COMPANYNO
AND TD.COMPANYNO = CD.COMPANYNO(+)
AND TD.VOUNO = CD.VOUNO(+)
AND TD.VOUDATE = CD.VOUDATE(+)
AND TD.NU_SERIAL_NO = CD.NU_SERIAL_NO(+)
AND TD.NU_SERIAL_NO = TDD.NU_SERIAL_NO(+)
AND TD.ACCCODE = AM.ACCCODE
AND TD.TRANTYPE IN ('JV', 'BR', 'BP', 'CN', , 'CR', 'CP')
AND NVL (TD.SECFLAG, 'N') = 'Y'
AND TDD.VOUNO(+) = TD.VOUNO
AND TDD.VOUDATE(+) = TD.VOUDATE
AND AM.COMPANYNO = :P_COMPANYNO
AND TDD.COMPANYNO(+) = :P_COMPANYNO
AND TD.ACCCODE = :P_BANKACCCODE
AND NVL (TD.SECFLAG, 'N') = 'Y'
AND TD.COMPANYNO = :P_COMPANYNO
ORDER BY
3,
2;
Why do you need to use the DISTINCT clause - is that a sign that you
do not have sufficient joins between the tables? It might be helpful
to post a DBMS_XPLAN for the query.
Charles Hooper
IT Manager/Oracle DBA
K&M Machine-Fabricating, Inc.