Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.misc -> Re: Which is fastest? To_Date.. or Trunc...

Re: Which is fastest? To_Date.. or Trunc...

From: Thomas Kyte <tkyte_at_us.oracle.com>
Date: Tue, 03 Aug 1999 14:32:47 GMT
Message-ID: <37a6f845.3665390@newshost.us.oracle.com>


A copy of this was sent to "R. Nightingale" <nighr_at_hotmail.com> (if that email address didn't require changing) On Sun, 1 Aug 1999 19:24:55 -0500, you wrote:

>Trunc simply sets the date to midnight by removing the fraction. I guess
>you could accomplish the same thing by using a To_Char(datefield,
>'YYYYMMDD') or something like that. I would imagine the Trunc approach
>would be quicker. The date datatype is already a 7-byte floating point
>number. You're welcome to post some benchmarks!
>--rn.
>

that is mostly correct. the part about a floating point number is wrong.

trunc of date zeroes out (logically zeroes out as shown below, zero-ing out the date results in 3 binary 1's being stored) the day, hour, minute, and second bytes of a date (last 3 bytes). for example:

SQL> create table t ( x date, y date ); Table created.

SQL> INSERT INTO T VALUE values ( sysdate, trunc(sysdate) ); 1 row created.

SQL> SELECT DUMP(X) x, DUMP(y) y from t;

X                                   Y
----------------------------------- -----------------------------------
Typ=12 Len=7: 119,199,8,3,11,11,47 Typ=12 Len=7: 119,199,8,3,1,1,1

A date in binary format contains seven bytes, as shown below

BYTE                              1    2     3   4    5      6      7
Meaning                     Century Year Month Day Hour Minute Second
Example
(for 30–NOV–1992,3:17 PM)       119  192    11  30   16     18      1

The century and year bytes are in an excess–100 notation. Dates Before Common Era (BCE) are less than 100. The era begins on 01–JAN–4712 BCE, which is Julian day 1. For this date, the century byte is 53, and the year byte is 88. The hour, minute, and second bytes are in excess–1 notation. The hour byte ranges from 1 to 24, the minute and second bytes from 1 to 60. If no time was specified when the date was created, the time defaults to midnight (1, 1, 1).

the trunc format would almost certainly be faster, not only because its fairly easy to perform (set the last 3 bytes to 1 rather then convert these 7 bytes into a nicely formatted string) but because it does not require any further conversions. If I code:

    if (date_field = trunc(another_date_field) ) then

we are comparing a DATE to a DATE (trunc returns a DATE). On the other hand, if I:

   if ( date_field = to_char(another_date_field,'dd-mon-yyyy') ) then

i introduced an implicit conversion into the code -- either date_field will be converted into a string or a to_date would be wrapped around the to_char() to make its result back into date.

This block shows that it is doing an extra implicit to_date on the the result of the to_char:

SQL> declare

  2          date_field date := trunc(sysdate);
  3          another_date_field date := sysdate;
  4  begin
  5          if ( date_field = to_char(another_date_field,'dd-mon-yyyy') )
  6          then
  7                  dbms_output.put_line( 'Are Equal' );
  8          else
  9                  dbms_output.put_line( 'Are not  Equal' );
 10          end if;
 11          if ( date_field = '03-aug-x999' )
 12          then
 13                  dbms_output.put_line( 'Are Equal' );
 14          else
 15                  dbms_output.put_line( 'Are not  Equal' );
 16          end if;

 17 end;
 18 /
Are Equal
declare
*
ERROR at line 1:
ORA-01858: a non-numeric character was found where a numeric was expected ORA-06512: at line 11

since the first one succeeded -- we can guess that it used an implicit to_date. Since the second one failed with a conversion error -- we can be assured it was doing the implicit conversion.

The trunc will not do that.

turning on sql_trace and running tkprof, we can see the difference is really quite large:

declare

    date_field date := trunc(sysdate);
    another_date_field date := sysdate; begin

    for i in 1 .. 10000 loop

        if ( date_field = to_char(another_date_field,'dd-mon-yyyy') )
        then
            null;
        end if;

    end loop;
end;

call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ----------

Parse        1      0.01       0.01          0          0          0           0
Execute      1      2.58       2.86          0          0          0           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      2.59       2.87          0          0          0           1


declare

    date_field date := trunc(sysdate);
    another_date_field date := sysdate; begin

    for i in 1 .. 10000 loop

        if ( date_field = trunc(another_date_field) )
        then
            null;
        end if;

    end loop;
end;

call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ----------

Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.15       0.19          0          0          0           1
Fetch        0      0.00       0.00          0          0          0           0
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        2      0.15       0.19          0          0          0           1



Similar differences in speed can be observed in SQL as well:

select count(*) from all_objects
where created = to_char(created,'dd-mon-yyyy')

call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ----------

Parse        1      0.00       0.00          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      3.70       4.63         21      33721          4           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      3.70       4.63         21      33721          4           1

********************************************************************************

 select count(*) from all_objects
 where created = trunc(created)

call count cpu elapsed disk query current rows ------- ------ -------- ---------- ---------- ---------- ---------- ----------

Parse        1      0.04       0.04          0          0          0           0
Execute      1      0.00       0.00          0          0          0           0
Fetch        2      1.55       1.74         10      33721          4           1
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total        4      1.59       1.78         10      33721          4           1




>Magnus <magnus.johansson_at_araby-dalbo.comREMOVETHIS> wrote in message
>news:37A2105D.C2106A39_at_eudoramail.comREMOVETHIS...
>> Hi,
>>
>> I have seen a couple of questions on comparing dates. Some recommend
>> To_Date and some recommend Trunc to get rid of the "time-part" of the
>> dates in the comparision. Does anyone know which is fastest when the
>> query runs?
>>
>> Thanks!
>>
>> /Magnus
>>
>

--
See http://govt.us.oracle.com/~tkyte/ for my columns 'Digging-in to Oracle8i'... Current article is "Part I of V, Autonomous Transactions" updated June 21'st  

Thomas Kyte                   tkyte_at_us.oracle.com
Oracle Service Industries     Reston, VA   USA

Opinions are mine and do not necessarily reflect those of Oracle Corporation Received on Tue Aug 03 1999 - 09:32:47 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US