Home » SQL & PL/SQL » SQL & PL/SQL » please help me in query...
please help me in query... [message #627917] Tue, 18 November 2014 02:49 Go to next message
hahaie
Messages: 194
Registered: May 2014
Senior Member
hello,
i have this code:
SELECT 'ali'name,SYSDATE birth_day FROM DUAL
  UNION 
SELECT 'arash'name,SYSDATE+1 birth_day FROM DUAL

i want name of person that date of birth is greater than others.
thanks
Re: please help me in query... [message #627920 is a reply to message #627917] Tue, 18 November 2014 03:08 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
WITH DATA AS (SELECT 'ali'name,SYSDATE birth_day FROM DUAL
  UNION 
SELECT 'arash'name,SYSDATE+1 birth_day FROM DUAL)
SELECT NAME, birth_day
FROM (SELECT NAME, birth_day, MAX(birth_day) OVER(PARTITION BY NULL) max_birth_day
      FROM DATA)
WHERE birth_day = max_birth_day;
Re: please help me in query... [message #627933 is a reply to message #627917] Tue, 18 November 2014 03:30 Go to previous messageGo to next message
Michel Cadot
Messages: 68645
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

SQL> with data as (
  2  SELECT 'ali'name,SYSDATE birth_day FROM DUAL
  3    UNION
  4  SELECT 'arash'name,SYSDATE+1 birth_day FROM DUAL
  5  )
  6  select name, birth_day
  7  from (select name, birth_day,
  8               rank() over (order by birth_day desc) rk
  9        from data)
 10  where rk = 1
 11  /
NAME  BIRTH_DAY
----- -------------------
arash 19/11/2014 10:29:34

1 row selected.

Re: please help me in query... [message #627941 is a reply to message #627920] Tue, 18 November 2014 03:45 Go to previous messageGo to next message
hahaie
Messages: 194
Registered: May 2014
Senior Member
thanks,
If 'over(partition by null)' is not used, there will be a problem?
Re: please help me in query... [message #627946 is a reply to message #627941] Tue, 18 November 2014 03:53 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
Why don't you try it and see?
Re: please help me in query... [message #627947 is a reply to message #627941] Tue, 18 November 2014 03:53 Go to previous messageGo to next message
Michel Cadot
Messages: 68645
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

Yes because if it is not there it is no more the analytic MAX function but the aggregate MAX function and you cannot then have the name and birthday together with the MAX value.

Re: please help me in query... [message #627951 is a reply to message #627917] Tue, 18 November 2014 04:13 Go to previous messageGo to next message
John Watson
Messages: 8931
Registered: January 2010
Location: Global Village
Senior Member
I took a simpler approach: joining the dat to an aggregation. Explain plan gives all three solutions
the same cost of 6 for materializing te view, but then my solution adds 4 as it hits the view several times.
The MC solution adds 1 as it does a WINDOW SORT PUSHED RANK, the CM solution adds zero.
Which I guess makes CM the winner /forum/fa/1964/0/
(except the OP is really the winner, for getting the work done for free)

Tests done on 12.1.0.2 Windows:
orclz>
orclz> set autot on exp
orclz> WITH DATA AS (SELECT 'ali'name,SYSDATE birth_day FROM DUAL
  2    UNION
  3  SELECT 'arash'name,SYSDATE+1 birth_day FROM DUAL)
  4  select name,birth_day from data where birth_day=(select max(birth_day) from data);

NAME  BIRTH_DAY
----- -------------------
arash 2014-11-19:10:05:57


Execution Plan
----------------------------------------------------------
Plan hash value: 3929412940

--------------------------------------------------------------------------------------------------------
| Id  | Operation                  | Name                      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |                           |     2 |    26 |    10  (20)| 00:00:01 |
|   1 |  TEMP TABLE TRANSFORMATION |                           |       |       |            |          |
|   2 |   LOAD AS SELECT           | SYS_TEMP_0FD9D6624_252B17 |       |       |            |          |
|   3 |    SORT UNIQUE             |                           |     2 |       |     6  (34)| 00:00:01 |
|   4 |     UNION-ALL              |                           |       |       |            |          |
|   5 |      FAST DUAL             |                           |     1 |       |     2   (0)| 00:00:01 |
|   6 |      FAST DUAL             |                           |     1 |       |     2   (0)| 00:00:01 |
|*  7 |   VIEW                     |                           |     2 |    26 |     2   (0)| 00:00:01 |
|   8 |    TABLE ACCESS FULL       | SYS_TEMP_0FD9D6624_252B17 |     2 |    26 |     2   (0)| 00:00:01 |
|   9 |    SORT AGGREGATE          |                           |     1 |     9 |            |          |
|  10 |     VIEW                   |                           |     2 |    18 |     2   (0)| 00:00:01 |
|  11 |      TABLE ACCESS FULL     | SYS_TEMP_0FD9D6624_252B17 |     2 |    26 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   7 - filter("BIRTH_DAY"= (SELECT MAX("BIRTH_DAY") FROM  (SELECT /*+ CACHE_TEMP_TABLE ("T1")
              */ "C0" "NAME","C1" "BIRTH_DAY" FROM "SYS"."SYS_TEMP_0FD9D6624_252B17" "T1") "DATA"))

orclz>
orclz> with data as (
  2     SELECT 'ali'name,SYSDATE birth_day FROM DUAL
  3       UNION
  4     SELECT 'arash'name,SYSDATE+1 birth_day FROM DUAL
  5     )
  6     select name, birth_day
  7     from (select name, birth_day,
  8                  rank() over (order by birth_day desc) rk
  9           from data)
 10    where rk = 1;

NAME  BIRTH_DAY
----- -------------------
arash 2014-11-19:10:06:37


Execution Plan
----------------------------------------------------------
Plan hash value: 539676268

---------------------------------------------------------------------------------
| Id  | Operation                | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |      |     2 |    52 |     7  (43)| 00:00:01 |
|*  1 |  VIEW                    |      |     2 |    52 |     7  (43)| 00:00:01 |
|*  2 |   WINDOW SORT PUSHED RANK|      |     2 |    26 |     7  (43)| 00:00:01 |
|   3 |    VIEW                  |      |     2 |    26 |     6  (34)| 00:00:01 |
|   4 |     SORT UNIQUE          |      |     2 |       |     6  (34)| 00:00:01 |
|   5 |      UNION-ALL           |      |       |       |            |          |
|   6 |       FAST DUAL          |      |     1 |       |     2   (0)| 00:00:01 |
|   7 |       FAST DUAL          |      |     1 |       |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RK"=1)
   2 - filter(RANK() OVER ( ORDER BY INTERNAL_FUNCTION("BIRTH_DAY") DESC
              )<=1)

orclz>
orclz> WITH DATA AS (SELECT 'ali'name,SYSDATE birth_day FROM DUAL
  2    UNION
  3  SELECT 'arash'name,SYSDATE+1 birth_day FROM DUAL)
  4  SELECT NAME, birth_day
  5  FROM (SELECT NAME, birth_day, MAX(birth_day) OVER(PARTITION BY NULL) max_birth_day
  6        FROM DATA)
  7  WHERE birth_day = max_birth_day;

NAME  BIRTH_DAY
----- -------------------
arash 2014-11-19:10:06:58


Execution Plan
----------------------------------------------------------
Plan hash value: 3553615855

-------------------------------------------------------------------------
| Id  | Operation        | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT |      |     2 |    44 |     6  (34)| 00:00:01 |
|*  1 |  VIEW            |      |     2 |    44 |     6  (34)| 00:00:01 |
|   2 |   WINDOW BUFFER  |      |     2 |    26 |     6  (34)| 00:00:01 |
|   3 |    VIEW          |      |     2 |    26 |     6  (34)| 00:00:01 |
|   4 |     SORT UNIQUE  |      |     2 |       |     6  (34)| 00:00:01 |
|   5 |      UNION-ALL   |      |       |       |            |          |
|   6 |       FAST DUAL  |      |     1 |       |     2   (0)| 00:00:01 |
|   7 |       FAST DUAL  |      |     1 |       |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("BIRTH_DAY"="MAX_BIRTH_DAY")

orclz>
orclz>
Re: please help me in query... [message #627964 is a reply to message #627951] Tue, 18 November 2014 05:25 Go to previous messageGo to next message
cookiemonster
Messages: 13920
Registered: September 2008
Location: Rainy Manchester
Senior Member
I've always been suspicious of plans against a two row table - You could write something ridiculously complex with cartesian joins thrown in and the cost would probably stay in single digits.
Create a table with a lot more rows and the explain plans suggest my version is better again:
Connected to:
Oracle Database 11g Release 11.2.0.3.0 - 64bit Production

SQL> set lines 250
SQL> CREATE TABLE testtab AS SELECT 'ali'||ROWNUM name,SYSDATE+ ROWNUM birth_day FROM DUAL CONNECT BY LEVEL < 10000;

Table created.

SQL> set autot on exp
SQL> select name,birth_day from testtab where birth_day=(select max(birth_day) from testtab);

NAME                                        BIRTH_DAY
------------------------------------------- ---------------
ali9999                                     20420404 114006


Execution Plan
----------------------------------------------------------
Plan hash value: 3232461785

-------------------------------------------------------------------------------
| Id  | Operation           | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |         |     1 |    32 |    16   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL  | TESTTAB |     1 |    32 |     8   (0)| 00:00:01 |
|   2 |   SORT AGGREGATE    |         |     1 |     9 |            |          |
|   3 |    TABLE ACCESS FULL| TESTTAB |  9999 | 89991 |     8   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("BIRTH_DAY"= (SELECT MAX("BIRTH_DAY") FROM "TESTTAB"
              "TESTTAB"))

Note
-----
   - dynamic sampling used for this statement (level=2)

SQL> select name, birth_day
from (select name, birth_day,
             rank() over (order by birth_day desc) rk
      from testtab)
where rk = 1;  2    3    4    5

NAME                                        BIRTH_DAY
------------------------------------------- ---------------
ali9999                                     20420404 114006


Execution Plan
----------------------------------------------------------
Plan hash value: 860320518

--------------------------------------------------------------------------------------------
| Id  | Operation                | Name    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |         |  9999 |   439K|       |    98   (2)| 00:00:02 |
|*  1 |  VIEW                    |         |  9999 |   439K|       |    98   (2)| 00:00:02 |
|*  2 |   WINDOW SORT PUSHED RANK|         |  9999 |   312K|   408K|    98   (2)| 00:00:02 |
|   3 |    TABLE ACCESS FULL     | TESTTAB |  9999 |   312K|       |     8   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RK"=1)
   2 - filter(RANK() OVER ( ORDER BY INTERNAL_FUNCTION("BIRTH_DAY") DESC )<=1)

Note
-----
   - dynamic sampling used for this statement (level=2)

SQL> SELECT NAME, birth_day
FROM (SELECT NAME, birth_day, MAX(birth_day) OVER(PARTITION BY NULL) max_birth_day
      FROM testtab)
WHERE birth_day = max_birth_day;  2    3    4

NAME                                        BIRTH_DAY
------------------------------------------- ---------------
ali9999                                     20420404 114006


Execution Plan
----------------------------------------------------------
Plan hash value: 2361134552

-------------------------------------------------------------------------------
| Id  | Operation           | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |         |  9999 |   400K|     8   (0)| 00:00:01 |
|*  1 |  VIEW               |         |  9999 |   400K|     8   (0)| 00:00:01 |
|   2 |   WINDOW BUFFER     |         |  9999 |   312K|     8   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| TESTTAB |  9999 |   312K|     8   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("BIRTH_DAY"="MAX_BIRTH_DAY")

Note
-----
   - dynamic sampling used for this statement (level=2)



However, if you actually run them:

SQL> set autot off;
SQL> set serveroutput on
SQL> DECLARE
l_start TIMESTAMP;
  2    3  l_name testtab.name%TYPE;
  4  l_birth_day testtab.birth_day%TYPE;
  5  BEGIN
  6
  7
  8    l_start := SYSTIMESTAMP;
  9
 10    FOR i IN 1..10000 LOOP
 11
 12       select name,birth_day INTO l_name, l_birth_day
 13       from testtab where birth_day=(select max(birth_day) from testtab);
 14
 15    END LOOP;

 16   17    dbms_output.put_line(' time aggregate '||to_char(SYSTIMESTAMP - l_start));

 18   19    l_start := SYSTIMESTAMP;
 20
 21    FOR i IN 1..10000 LOOP
 22
 23      select name, birth_day INTO l_name, l_birth_day
 24      from (select name, birth_day,
 25                   rank() over (order by birth_day desc) rk
 26            from testtab)
 27      where rk = 1;
 28
 29    END LOOP;
 30
 31    dbms_output.put_line(' time rank'||to_char(SYSTIMESTAMP - l_start));

 32   33    l_start := SYSTIMESTAMP;

 34   35    FOR i IN 1..10000 LOOP

 36   37      SELECT NAME, birth_day INTO l_name, l_birth_day
 38      FROM (SELECT NAME, birth_day, MAX(birth_day) OVER(PARTITION BY NULL) max_birth_day
 39            FROM testtab)
 40      WHERE birth_day = max_birth_day;
 41
 42    END LOOP;

 43   44    dbms_output.put_line(' time anlytic max'||to_char(SYSTIMESTAMP - l_start));
 45
 46  END;
 47  /
time aggregate +000000000 00:00:17.180089000
time rank+000000000 00:00:41.575387000
time anlytic max+000000000 00:00:55.829415000

PL/SQL procedure successfully completed.

SQL>

Turns out the aggregate is significantly faster. In fact that makes a complete mockery of the explain plans, since according to them the sqls in order slowest to fastest is:
rank
max aggregate
max analytic

In reality it is:
max analytic
rank
max aggregate

However, if you make it a two row table you get:
time aggregate +000000000 00:00:01.181640000
time rank+000000000 00:00:01.148062000
time analytic max+000000000 00:00:01.149203000


So looking at that I'd favour the aggregate, it's only slower when the difference isn't particularly meaningful
Re: please help me in query... [message #627970 is a reply to message #627964] Tue, 18 November 2014 06:07 Go to previous message
Michel Cadot
Messages: 68645
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator

Quote:
I've always been suspicious of plans against a two row table -


And against tables fill with ordered data... : )

Same version (11.2.0.3.0 but Windows 32-bit):
SQL> CREATE TABLE testtab AS
  2  SELECT 'ali'||ROWNUM name,SYSDATE+ dbms_random.value(-1000,1000) birth_day
  3  FROM DUAL CONNECT BY LEVEL < 10000;

Table created.

SQL> exec dbms_stats.gather_table_stats (user, 'TESTTAB');

PL/SQL procedure successfully completed.

SQL> set autot on exp
SQL> select name,birth_day from testtab where birth_day=(select max(birth_day) from testtab);
NAME                                        BIRTH_DAY
------------------------------------------- -------------------
ali3638                                     14/08/2017 07:37:13

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3232461785

-------------------------------------------------------------------------------
| Id  | Operation           | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |         |     1 |    16 |    18   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL  | TESTTAB |     1 |    16 |     9   (0)| 00:00:01 |
|   2 |   SORT AGGREGATE    |         |     1 |     8 |            |          |
|   3 |    TABLE ACCESS FULL| TESTTAB |  9999 | 79992 |     9   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("BIRTH_DAY"= (SELECT MAX("BIRTH_DAY") FROM "TESTTAB"
              "TESTTAB"))

SQL> select name, birth_day
  2  from (select name, birth_day,
  3               rank() over (order by birth_day desc) rk
  4        from testtab)
  5  where rk = 1;
NAME                                        BIRTH_DAY
------------------------------------------- -------------------
ali3638                                     14/08/2017 07:37:13

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 860320518

--------------------------------------------------------------------------------------------
| Id  | Operation                | Name    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |         |  9999 |   439K|       |    65   (2)| 00:00:01 |
|*  1 |  VIEW                    |         |  9999 |   439K|       |    65   (2)| 00:00:01 |
|*  2 |   WINDOW SORT PUSHED RANK|         |  9999 |   156K|   248K|    65   (2)| 00:00:01 |
|   3 |    TABLE ACCESS FULL     | TESTTAB |  9999 |   156K|       |     9   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("RK"=1)
   2 - filter(RANK() OVER ( ORDER BY INTERNAL_FUNCTION("BIRTH_DAY") DESC )<=1)

SQL>  SELECT NAME, birth_day
  2  FROM (SELECT NAME, birth_day, MAX(birth_day) OVER(PARTITION BY NULL) max_birth_day
  3        FROM testtab)
  4  WHERE birth_day = max_birth_day;
NAME                                        BIRTH_DAY
------------------------------------------- -------------------
ali3638                                     14/08/2017 07:37:13

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 2361134552

-------------------------------------------------------------------------------
| Id  | Operation           | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |         |  9999 |   400K|     9   (0)| 00:00:01 |
|*  1 |  VIEW               |         |  9999 |   400K|     9   (0)| 00:00:01 |
|   2 |   WINDOW BUFFER     |         |  9999 |   156K|     9   (0)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| TESTTAB |  9999 |   156K|     9   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("BIRTH_DAY"="MAX_BIRTH_DAY")

SQL>
SQL> DECLARE
  2    l_start TIMESTAMP;
  3    l_name testtab.name%TYPE;
  4    l_birth_day testtab.birth_day%TYPE;
  5  BEGIN
  6    l_start := SYSTIMESTAMP;
  7    FOR i IN 1..10000 LOOP
  8      select name,birth_day INTO l_name, l_birth_day
  9      from testtab where birth_day=(select max(birth_day) from testtab);
 10    END LOOP;
 11    dbms_output.put_line(' time aggregate '||to_char(SYSTIMESTAMP - l_start));
 12    l_start := SYSTIMESTAMP;
 13    FOR i IN 1..10000 LOOP
 14      select name, birth_day INTO l_name, l_birth_day
 15      from (select name, birth_day,
 16                   rank() over (order by birth_day desc) rk
 17            from testtab)
 18      where rk = 1;
 19    END LOOP;
 20    dbms_output.put_line(' time rank '||to_char(SYSTIMESTAMP - l_start));
 21    l_start := SYSTIMESTAMP;
 22    FOR i IN 1..10000 LOOP
 23      SELECT NAME, birth_day INTO l_name, l_birth_day
 24      FROM (SELECT NAME, birth_day, MAX(birth_day) OVER(PARTITION BY NULL) max_birth_day
 25            FROM testtab)
 26      WHERE birth_day = max_birth_day;
 27    END LOOP;
 28    dbms_output.put_line(' time anlytic max '||to_char(SYSTIMESTAMP - l_start));
 29  END;
 30  /
 time aggregate +000000000 00:00:10.455000000
 time rank +000000000 00:00:17.667000000
 time anlytic max +000000000 00:00:55.754000000

PL/SQL procedure successfully completed.

"Time rank" is closer to "time aggregate" than to "time analytic max" like for you.

Previous Topic: Deferred transaction
Next Topic: error when trying to refresh materialized view
Goto Forum:
  


Current Time: Fri Apr 26 05:31:31 CDT 2024