Vladimir,

Thanks I hadn't considered || as a function, though it is.

At first, I was going to take your word for it, but then decided
this would be an interesting test. :)

But first, I agree, you must know what you're looking for, neither
of these would work in all situations.

First, I built some test data:

--------------------------------------
drop table emp;

create table emp( ename, job  )
as
select table_name, column_name
from dba_tab_columns
where rownum < 1001
/

alter table emp add ( mydate date );
update emp set mydate = sysdate;
commit;

declare
   v_date date;
begin

   for f in 1 .. 5
   loop
      insert into emp
      select ename, job, sysdate
      from emp;
      dbms_lock.sleep(1);
   end loop;

   insert into emp
   select ename, job, null
   from emp;

end;
/

create index emp_idx on emp(ename, job, mydate);
-----------------------------

This creates 64000 rows in emp.

For testing, I'm using Tom Kytes run_stats.sql and test_harness.sql.

The URL is something like govt.oracle.com/~tkyte/run_stats.html

Not sure, because my internet connection is down as I write this.

Below is the test harness code I used:

-----------------------------------
-- test_harness.sql
-- from Tom Kyte - asktom.oracle.com/~tkyte/runstats.html
-- see ~/oracle/dba/run_stats for all files


declare
        l_start number;
        --add any other variables you need here for the test... 
        v_count integer;
begin
        delete from run_stats;
        commit;
        -- start by getting a snapshot of the v$ tables
        insert into run_stats select 'before', stats.* from stats;

        -- and start timing...
        l_start := dbms_utility.get_time;

        -- for things that take a very small amount of time, I like to 
        -- loop over it time and time again, to measure something "big"
        -- if what you are testing takes a long time, loop less or maybe
        -- not at all
        for i in 1 .. 10
        loop 
                select count(distinct(ename||job||mydate)) into v_count
                from emp;
        end loop;

        dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs' );
   
        -- get another snapshot and start timing again... 
        insert into run_stats select 'after 1', stats.* from stats;

        l_start := dbms_utility.get_time;

        for i in 1 .. 10
        loop 
                SELECT COUNT(*) into v_count
                FROM (
                        SELECT DISTINCT
                                ename, job, mydate
                        FROM emp
                );
        end loop;

        dbms_output.put_line( (dbms_utility.get_time-l_start) || ' hsecs' );
        insert into run_stats select 'after 2', stats.* from stats;
end;
/

----------------------------------

Now the results.  Run 1 uses CONCAT, Run 2 uses 
an inline view with Group by.

22:13:02 sherlock - jkstill@ts01 SQL> @th
1691 hsecs
2032 hsecs

PL/SQL procedure successfully completed.

22:13:49 sherlock - jkstill@ts01 SQL> @run_stats

NAME                                           RUN1       RUN2       DIFF
---------------------------------------- ---------- ---------- ----------
STAT...consistent gets                         3378       3379          1
STAT...db block changes                          17         16         -1
LATCH.undo global data                            3          4          1
STAT...calls to get snapshot scn: kcmgss         23         22         -1
STAT...parse time elapsed                         0          1          1
STAT...parse time cpu                             0          1          1
STAT...deferred (CURRENT) block cleanout          3          2         -1
 applications

LATCH.active checkpoint queue latch               5          7          2
LATCH.virtual circuit queues                      2          0         -2
LATCH.redo allocation                            13         18          5
LATCH.redo writing                               22         27          5
LATCH.checkpoint queue latch                     27         34          7
LATCH.messages                                   33         44         11
LATCH.session allocation                         22         38         16
STAT...free buffer requested                    779        761        -18
LATCH.session idle bit                           11         31         20
LATCH.shared pool                                 3         27         24
LATCH.multiblock read objects                   312        338         26
STAT...prefetched blocks                        607        578        -29
STAT...redo size                              20964      21008         44
STAT...enqueue requests                         441        544        103
STAT...enqueue releases                         440        544        104
LATCH.sort extent pool                          495        599        104
LATCH.library cache                             241        389        148
LATCH.enqueue hash chains                       880       1096        216
STAT...recursive cpu usage                     1592       1908        316
LATCH.enqueues                                 1771       2211        440
STAT...db block gets                            954       1494        540
STAT...session logical reads                   4332       4873        541
LATCH.cache buffers chains                    12988      14905       1917
STAT...physical reads                          5927       8310       2383
STAT...physical writes                         5159       7560       2401
STAT...physical writes non checkpoint          5159       7560       2401
STAT...physical reads direct                   5159       7560       2401
STAT...physical writes direct                  5159       7560       2401

35 rows selected.

Though not a dramatic difference, the CONCAT was faster
and less resource intensive than the inline view with GROUP BY.

:)

Jared



On Wednesday 29 January 2003 16:08, Vladimir Begun wrote:
> [EMAIL PROTECTED] wrote:
> >>I can do a COUNT(DISTINCT ename || job), but that doesn't seem to be
> >
> > elegant
> >
> >>way of doing it.
> >
> > elegant = simple, concise, easy to understand.
> >
> > Looks elegant to me.
>
> Jared, it just looks that that...
>
> CONCAT = || yet another function call, yet another piece of
> code, yet another byte of memory... If you have more than
> two columns? If some of those are numeric, date? If ename
> is Smith and job is Smith and both can be nullable? :)
> NVLs? NVL2s? I think this approach is only valid when one
> really understands what she/he is looking for. Could be
> good for FBI, CHECK constraints but it's very risky and
> resource consuming (depends, can be neglected) for
> queries.
>
> It's better to write something that just looks ugly but
> works faster and reliably. Simple, fast, and covers all
> 'strange' cases:
>
> SELECT COUNT(*)
>    FROM (
>         SELECT DISTINCT
>                ename
>              , job
>           FROM emp
>         )
> /
>
> Regards,
-- 
Please see the official ORACLE-L FAQ: http://www.orafaq.net
-- 
Author: Jared Still
  INET: [EMAIL PROTECTED]

Fat City Network Services    -- 858-538-5051 http://www.fatcity.com
San Diego, California        -- Mailing list and web hosting services
---------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: [EMAIL PROTECTED] (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB ORACLE-L
(or the name of mailing list you want to be removed from).  You may
also send the HELP command for other information (like subscribing).

Reply via email to