Home » RDBMS Server » Performance Tuning » Performance access direct table vs view (Oracle 10g / Windows XP)
Performance access direct table vs view [message #534856] Fri, 09 December 2011 13:20 Go to next message
eeriehunk
Messages: 16
Registered: May 2009
Junior Member
Hello Folks,
If you have 3 tables (yr09, yr10,yr11) one with 2009 data, 2010 and 2011 data respectively. And a view (vw_yr091011) with a "union all" on all three.
Question: Will the performance be same for the following two queries ?
Question: Will Oracle read all 3 tables in the view when we search for only one year ?

select count(*) from yr09 
where year = 2009;

-- vs

select count(*) from vw_yr091011
where year = 2009;


The following link says yes, the performance remains the same.

Link: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:21547067945222
Search for post : August 21, 2007 - 12pm

when I tried on a volume of 14000 records. The count came out same but the view took 50 more sec. And the explain plan shows it accessed all three tables. Did I miss something.

Kindly provide insight on this please.

Regards,
Aj
Re: Performance access direct table vs view [message #534858 is a reply to message #534856] Fri, 09 December 2011 13:49 Go to previous messageGo to next message
BlackSwan
Messages: 26766
Registered: January 2009
Location: SoCal
Senior Member
>Kindly provide insight on this please.
The design is flawed.
It should be single table which contains DATE datatype column to hold the "year".
Re: Performance access direct table vs view [message #534862 is a reply to message #534856] Fri, 09 December 2011 14:50 Go to previous messageGo to next message
Michel Cadot
Messages: 68641
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator
Quote:
And the explain plan shows it accessed all three tables. Did I miss something.


Maybe you don't read the explain plan correctly.

For any peformances question, please read http://www.orafaq.com/forum/mv/msg/84315/433888/102589/#msg_433888 and post the required information.

Regards
Michel
Re: Performance access direct table vs view [message #534867 is a reply to message #534862] Fri, 09 December 2011 15:43 Go to previous messageGo to next message
eeriehunk
Messages: 16
Registered: May 2009
Junior Member
Yes the Explain Plan does show all 3 tables accessed. However, didn't wanted give up as I could have been wrong creating the view or might have missed something.

Appreciate all inputs.
Thank you,
Aj
Re: Performance access direct table vs view [message #534872 is a reply to message #534867] Fri, 09 December 2011 16:38 Go to previous messageGo to next message
Roachcoach
Messages: 1576
Registered: May 2010
Location: UK
Senior Member
What did you execute first? View or table?

I'm agree with blackswan, though depending if the volumes need it (I assume noted volumes are test/dev and are significantly lower than production) partitioning the table (if you have the option) may be the way to go.

Nb: the only explain plan to trust is one sql*plus puts out. I've seen (for example) SQL developer give bad (i.e. inaccurate) plans for older DB versions. Certainly from the GUI option. Not on work rig atm but I assume dbms_xplan in raw code is ok.
Re: Performance access direct table vs view [message #534887 is a reply to message #534867] Fri, 09 December 2011 23:51 Go to previous messageGo to next message
Michel Cadot
Messages: 68641
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator
Quote:
Yes the Explain Plan does show all 3 tables accessed. However, didn't wanted give up as I could have been wrong creating the view or might have missed something.


Once again maybe (surely) you don't correctly read the explain plan.
Post it!

Regards
Michel
Re: Performance access direct table vs view [message #534913 is a reply to message #534887] Sat, 10 December 2011 02:49 Go to previous messageGo to next message
John Watson
Messages: 8929
Registered: January 2010
Location: Global Village
Senior Member
Hello - I've just been doing a little experiment on this. Here is my test case:
conn / as sysdba
drop user jon cascade;
grant dba to jon identified by jon;
conn jon/jon

create table yr09(year number);
create table yr10(year number);
create table yr11(year number);

exec dbms_Stats.set_table_stats('JON','YR09',numrows=>1000000)
exec dbms_Stats.set_table_stats('JON','YR10',numrows=>1000000)
exec dbms_Stats.set_table_stats('JON','YR11',numrows=>1000000)

create view vw_yr091011 as 
select * from yr09
union all
select * from yr10
union all
select * from yr11;

explain plan for
select count(*) from vw_yr091011
where year = 2009;
select * from table(dbms_xplan.display);

alter table yr09 add constraint ck09 check(year=2009);
alter table yr10 add constraint ck10 check(year=2010);
alter table yr11 add constraint ck11 check(year=2011);

explain plan for
select count(*) from vw_yr091011
where year = 2009;
select * from table(dbms_xplan.display);

Without the check constraints I get this:
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------

Plan hash value: 1276644899

--------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |     1 |    13 |   102  (19)| 00:00:02 |
|   1 |  SORT AGGREGATE              |             |     1 |    13 |            |          |
|   2 |   VIEW                       | VW_YR091011 |    96 |  1248 |   102  (19)| 00:00:02 |
|   3 |    UNION-ALL                 |             |       |       |            |          |
|*  4 |     TABLE ACCESS STORAGE FULL| YR09        | 10000 |   126K|    35  (18)| 00:00:01 |
|*  5 |     TABLE ACCESS STORAGE FULL| YR10        | 10000 |   126K|    35  (18)| 00:00:01 |
|*  6 |     TABLE ACCESS STORAGE FULL| YR11        | 10000 |   126K|    35  (18)| 00:00:01 |
--------------------------------------------------------------------------------------------

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

   4 - storage("YEAR"=2009)
       filter("YEAR"=2009)
   5 - storage("YEAR"=2009)
       filter("YEAR"=2009)
   6 - storage("YEAR"=2009)
       filter("YEAR"=2009)

No surprise there. With the constraints I get this:
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------

Plan hash value: 2941325854

---------------------------------------------------------------------------------------------
| Id  | Operation                     | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |             |     1 |    13 |   102  (19)| 00:00:02 |
|   1 |  SORT AGGREGATE               |             |     1 |    13 |            |          |
|   2 |   VIEW                        | VW_YR091011 |    96 |  1248 |   102  (19)| 00:00:02 |
|   3 |    UNION-ALL                  |             |       |       |            |          |
|*  4 |     TABLE ACCESS STORAGE FULL | YR09        | 10000 |   126K|    35  (18)| 00:00:01 |
|*  5 |     FILTER                    |             |       |       |            |          |
|*  6 |      TABLE ACCESS STORAGE FULL| YR10        | 10000 |   126K|    35  (18)| 00:00:01 |
|*  7 |     FILTER                    |             |       |       |            |          |
|*  8 |      TABLE ACCESS STORAGE FULL| YR11        | 10000 |   126K|    35  (18)| 00:00:01 |
---------------------------------------------------------------------------------------------

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

   4 - storage("YEAR"=2009)
       filter("YEAR"=2009)
   5 - filter(NULL IS NOT NULL)
   6 - storage("YEAR"=2009)
       filter("YEAR"=2009)
   7 - filter(NULL IS NOT NULL)
   8 - storage("YEAR"=2009)
       filter("YEAR"=2009)

What is this telling me? The optimizer appears to be aware that the constraint means there can be no matching rows in two of the tables, because it is adding a filter NULL IS NOT NULL. Does this mean that two of the tables are not addressed at all? Or is it merely a fast way of throwing out all their rows?

[update: this is 11.2.0.3 EE, 32bit Vista Home Premium]

[Updated on: Sat, 10 December 2011 02:51]

Report message to a moderator

Re: Performance access direct table vs view [message #534916 is a reply to message #534913] Sat, 10 December 2011 03:16 Go to previous messageGo to next message
Michel Cadot
Messages: 68641
Registered: March 2007
Location: Nanterre, France, http://...
Senior Member
Account Moderator
Quote:
Does this mean that two of the tables are not addressed at all?

Yes.
It is easy to see it using 10046 raw trace and see which blocks are read.

Regards
Michel
Re: Performance access direct table vs view [message #534923 is a reply to message #534916] Sat, 10 December 2011 05:23 Go to previous messageGo to next message
John Watson
Messages: 8929
Registered: January 2010
Location: Global Village
Senior Member
Sussed.
So, Eeriehunk, to conclude: I believe your view can be as efficient as querying the table directly, if you have check constraints that tell the optimizer what is going on. I think you'll have to test a lot of queries to be sure they all work as expected.

In case anyone is interested, I modified my test case to have real data and to run the query:
insert into yr09 select 2009 from dual connect by (rownum <=1000000);
insert into yr10 select 2010 from dual connect by (rownum <=1000000);
insert into yr11 select 2011 from dual connect by (rownum <=1000000);

exec dbms_stats.gather_table_stats('JON','YR09')
exec dbms_stats.gather_table_stats('JON','YR10')
exec dbms_stats.gather_table_stats('JON','YR11')

set autot on
select count(*) from vw_yr091011
where year = 2009;

alter table yr09 drop constraint ck09;
alter table yr10 drop constraint ck10;
alter table yr11 drop constraint ck11;

select count(*) from vw_yr091011
where year = 2009;
With the constraints,
Execution Plan
----------------------------------------------------------
Plan hash value: 2941325854

---------------------------------------------------------------------------------------------
| Id  | Operation                     | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |             |     1 |     4 |  1346   (2)| 00:00:17 |
|   1 |  SORT AGGREGATE               |             |     1 |     4 |            |          |
|   2 |   VIEW                        | VW_YR091011 |  1000K|  3906K|  1346   (2)| 00:00:17 |
|   3 |    UNION-ALL                  |             |       |       |            |          |
|*  4 |     TABLE ACCESS STORAGE FULL | YR09        |   999K|  3905K|   450   (2)| 00:00:06 |
|*  5 |     FILTER                    |             |       |       |            |          |
|*  6 |      TABLE ACCESS STORAGE FULL| YR10        |     1 |     4 |   450   (2)| 00:00:06 |
|*  7 |     FILTER                    |             |       |       |            |          |
|*  8 |      TABLE ACCESS STORAGE FULL| YR11        |     1 |     4 |   450   (2)| 00:00:06 |
---------------------------------------------------------------------------------------------

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

   4 - storage("YEAR"=2009)
       filter("YEAR"=2009)
   5 - filter(NULL IS NOT NULL)
   6 - storage("YEAR"=2009)
       filter("YEAR"=2009)
   7 - filter(NULL IS NOT NULL)
   8 - storage("YEAR"=2009)
       filter("YEAR"=2009)


Statistics
----------------------------------------------------------
         29  recursive calls
          1  db block gets
       1606  consistent gets
       1568  physical reads
          0  redo size
        422  bytes sent via SQL*Net to client
        420  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

and without,
Execution Plan
----------------------------------------------------------
Plan hash value: 1276644899

-------------------------------------------------------------------------------------------
| Id  | Operation                    | Name        | Rows  | Bytes | Cost (%CPU)| Time
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |             |     1 |     4 |  1346   (2)| 00:00:17
|   1 |  SORT AGGREGATE              |             |     1 |     4 |            |
|   2 |   VIEW                       | VW_YR091011 |  1000K|  3906K|  1346   (2)| 00:00:17
|   3 |    UNION-ALL                 |             |       |       |            |
|*  4 |     TABLE ACCESS STORAGE FULL| YR09        |   999K|  3905K|   450   (2)| 00:00:06
|*  5 |     TABLE ACCESS STORAGE FULL| YR10        |     1 |     4 |   450   (2)| 00:00:06
|*  6 |     TABLE ACCESS STORAGE FULL| YR11        |     1 |     4 |   450   (2)| 00:00:06
-------------------------------------------------------------------------------------------

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

   4 - storage("YEAR"=2009)
       filter("YEAR"=2009)
   5 - storage("YEAR"=2009)
       filter("YEAR"=2009)
   6 - storage("YEAR"=2009)
       filter("YEAR"=2009)


Statistics
----------------------------------------------------------
         37  recursive calls
          3  db block gets
       4858  consistent gets
       4704  physical reads
          0  redo size
        422  bytes sent via SQL*Net to client
        420  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
         15  sorts (memory)
          0  sorts (disk)
          1  rows processed

The consistent gets figures are conclusive.

Re: Performance access direct table vs view [message #537351 is a reply to message #534923] Tue, 27 December 2011 20:23 Go to previous message
Kevin Meade
Messages: 2103
Registered: December 1999
Location: Connecticut USA
Senior Member
In the old days we did what was called a manually partitioned view:

create or replace view vw_yr091011
as
select 2009 year,c2,c3... from yr09
union all
select 2010 year,c2,c3... from yr10
union all
select 2011 year,c2,c3... from yr11
/

select * from vw_yr091011 where year = 2009;


will now short circuit and only read the 2009 table at execution time. Only yr09 will be accessed.

You should easily be able to verify this with some simple timings. The manually partitioned view should be noticibly faster than the original view shown by someone above. Once you verify this, you can use the timing of this view to determine if other techniques (like the constraints method) are giving the same effect.

I have 11g 11.2.0.1 for Windows7 on my home computer. Consider the following query plan I get from autotrace when I try your situation using the manually partitioned view approach:

SQL> l
  1* select * from vw_yr091011 where year = 2009
SQL> /

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 1215290558

------------------------------------------------------------------------------------
| Id  | Operation            | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |     3 |    60 |     2   (0)| 00:00:01 |
|   1 |  VIEW                | VW_YR091011 |     3 |    60 |     2   (0)| 00:00:01 |
|   2 |   UNION-ALL          |             |       |       |            |          |
|   3 |    TABLE ACCESS FULL | YR09        |     1 |    17 |     2   (0)| 00:00:01 |
|*  4 |    FILTER            |             |       |       |            |          |
|   5 |     TABLE ACCESS FULL| YR10        |     1 |    17 |     2   (0)| 00:00:01 |
|*  6 |    FILTER            |             |       |       |            |          |
|   7 |     TABLE ACCESS FULL| YR11        |     1 |    17 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------------

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

   4 - filter(NULL IS NOT NULL)
   6 - filter(NULL IS NOT NULL)

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


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          0  consistent gets
          0  physical reads
          0  redo size
        398  bytes sent via SQL*Net to client
        509  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

SQL>


Note in particular the two filter lines added to the query:

   4 - filter(NULL IS NOT NULL)
   6 - filter(NULL IS NOT NULL)


The Oracle parser added these lines to the orignal query as a cheap way to get execution to skip access of the corresponding tables. I would expect that yr10 and yr11 would not be accessed to answer the above query and that only yr09 would be touched. This will of course be relected in shorter runtimes. If other techinques achieve the same timings or show similar query predicate alterations, then you are good to go.

Quote:
John Watson showed the above when he demonstrated in his posts to this thread, that constraints produce the same filter expressions. This was nice John, I am going to use this example in a class I am writing for my company, thanks man.


As to your original question, technically there will be fewer cpu cycles spent in parsing your query if you are accessing a table directly rather than using a view. But Oracle parser has gotten very good at query merging over the years so this cost gets cheaper with each release. The actual modified query will be just as fast regardless of if it came from tables or views. So overall, unless your query is a centisecond query, you will not be hindered by using views in any currently supported version of the database.

Kevin
Previous Topic: Query cost
Next Topic: Performance Tuning
Goto Forum:
  


Current Time: Fri Apr 19 15:27:45 CDT 2024