10	  Things	  You	  Might	  Not	  Know	         About	  Oracle	  Indexes	                 Richard	  Foote	                ...
Richard	  Foote	  •    Working	  in	  IT	  for	  25	  years	  (scary	  stuff)	  •    Working	  with	  Oracle	  for	  15	  y...
1.	  Delete	  More	  Rows	  To	  Reduce	           Deleted	  Space	  Within	  An	  Index	  •  Very	  common	  advice	  to	...
1:	  If	  deleted	  space	  >20%,	  delete	  some	  more!!	  SQL>	  create	  table	  radiohead	  (id	  number,	  name	  va...
1:	  If	  deleted	  space	  >20%,	  delete	  some	  more!!	  SQL>	  delete	  radiohead	  where	  mod(id,10)	  IN	  (2,4,6)...
1:	  If	  deleted	  space	  >20%,	  delete	  some	  more!!	  Well,	  let’s	  just	  delete	  some	  more	  rows	  ...	  SQ...
1:	  If	  deleted	  space	  >20%,	  delete	  some	  more!!	  •  What	  many	  don’t	  realise	  is	  that	  in	  most	  sc...
2.Bitmap	  Index	  High	  Cardinality	  Columns	  	  •  Very	  common	  advice	  to	  only	  use	  Bitmap	  Index	  with	 ...
2.Bitmap	  Index	  High	  Cardinality	  Columns	  	  SQL>	  CREATE	  TABLE	  big_dwh_table	  (id	  NUMBER,	  album_id	  NU...
2.Bitmap	  Index	  High	  Cardinality	  Columns	  	   OK,	  let’s	  start	  with	  a	  B-­‐Tree	  Index	  SQL>	  CREATE	  ...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	  SQL>	  SELECT	  *	  FROM	  big_dwh_table	  WHERE	  album_id	  =	  ...
2.Bitmap	  Index	  High	  Cardinality	  Columns	  	  Let’s	  create	  same	  index	  as	  a	  Bitmap	  Index.	  However,	 ...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	  SQL>	  SELECT	  *	  FROM	  big_dwh_table	  WHERE	  album_id	  =	  ...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	  The	  Clustering	  Factor	  of	  an	  index	  has	  a	  big	  impa...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	  Create	  a	  copy	  of	  the	  table	  but	  this	  Fme	  clustere...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	  SQL>	  SELECT	  i.index_name,	  i.index_type,	  t.num_rows	  "TABL...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	  SQL>	  SELECT	  *	  FROM	  big_dwh_table_2	  WHERE	  album_id	  =	...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	    Of	  course,	  this	  will	  also	  impact	  Clustering	  Factor...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	  SQL>	  SELECT	  *	  FROM	  big_dwh_table_2	  WHERE	  album_id	  =	...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	  Table	  containing	  person	  names,	  using	  freshly	  rebuilt	 ...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	  Bitmap	  Indexes	  are	  actually	  substanFally	  smaller	  and	 ...
2.	  Bitmap	  Index	  High	  Cardinality	  Columns	  	  •  If	  you	  only	  use	  Bitmap	  Indexes	  for	  low	  cardinal...
3.	  B-­‐Tree	  Index	  Low	  Cardinality	  Columns	  •  Generally	  B-­‐Tree	  Indexes	  more	  suitable	  for	  columns	...
3.	  B-­‐Tree	  Index	  Low	  Cardinality	  Columns	   SQL>	  create	  table	  bowie	  (id	  number,	  code	  number,	  na...
3.	  B-­‐Tree	  Index	  Low	  Cardinality	  Columns	  SQL>	  select	  blevel,	  leaf_blocks,	  disFnct_keys	  from	  dba_i...
3.	  B-­‐Tree	  Index	  Low	  Cardinality	  Columns	  SQL>	  select	  *	  from	  bowie	  where	  code	  =	  42;	  	  	  10...
4.	  Index	  Just	  Which	  Column	  Values	  You	                                Want	  •  By	  default,	  all	  values	 ...
4.	  Just	  index	  some	  column	  values	  SQL>	  CREATE	  TABLE	  index_some_stuff	  (id	  number,	  status	  varchar2(2...
4.	  Just	  index	  some	  column	  values	  SQL>	  CREATE	  INDEX	  index_some_stuff_i_1	  ON	  index_some_stuff(status);	 ...
4.	  Just	  index	  some	  column	  values	  But	  why	  bother	  indexing	  all	  the	  common	  values	  when	  they’ll	...
4.	  Just	  index	  some	  column	  values	  SQL>	  SELECT	  *	  FROM	  bowie.index_some_stuff	  	  	  	  	  	  	  	  	  	 ...
4.	  Just	  index	  some	  column	  values	  Can	  use	  zero	  sized	  unusable	  indexes	  to	  your	  advantage	  to	  ...
4.	  Just	  index	  some	  column	  values	  SQL>	  select	  index_name,	  leaf_blocks	  from	  dba_indexes	  where	  inde...
4.	  Just	  index	  some	  column	  values	  SQL>	  select	  *	  from	  bowie_stuff	  where	  processed	  =	  NO;	  	  Exec...
4.	  Just	  index	  some	  column	  values	  However	  in	  11g	  R2,	  if	  we	  now	  recreate	  the	  index	  as	  a	  ...
4.	  Just	  index	  some	  column	  values	  We	  now	  only	  use	  a	  fracFon	  of	  the	  storage	  for	  the	  index	...
4.	  Just	  index	  some	  column	  values	  SQL>	  select	  *	  from	  bowie_stuff	  where	  processed	  =	  NO;	  	  Exec...
5.	  100%	  Index	  SelecFvity	  •  Generally	  indexes	  only	  process	  a	  “small”	  %	  of	     overall	  data	  •  C...
5.	  100%	  Index	  SelecFvity	  SQL>	  create	  table	  ziggy	  (id	  number,	  name	  varchar2(30));	  Table	  created.	...
5.	  100%	  Index	  SelecFvity	  SQL>	  select	  id	  from	  ziggy	  where	  id	  >	  1;	  	  	  1000	  rows	  selected.	 ...
5.	  100%	  Index	  SelecFvity	  SQL>	  select	  *	  from	  ziggy	  where	  id	  >	  1;	  	  	  1000	  rows	  selected.	  ...
5.	  100%	  Index	  SelecFvity	  SQL>	  CREATE	  TABLE	  big_dwh_table_2	  AS	  SELECT	  *	  FROM	  big_dwh_table	  	  	  ...
5.	  100%	  Index	  SelecFvity	  SQL>	  SELECT	  *	  FROM	  big_dwh_table	  WHERE	  album_id	  BETWEEN	  10	  AND	  20	  O...
5.	  100%	  Index	  SelecFvity	  SQL>	  SELECT	  *	  FROM	  big_dwh_table	  WHERE	  album_id	  BETWEEN	  10	  AND	  20	  	...
5.	  100%	  Index	  SelecFvity	  SQL>	  SELECT	  *	  FROM	  big_dwh_table	  WHERE	  album_id	  BETWEEN	  1	  AND	  10000	 ...
5.	  100%	  Index	  SelecFvity	  SQL>	  SELECT	  *	  FROM	  big_dwh_table	  ORDER	  BY	  album_id;	  	  1000000	  rows	  s...
5.	  100%	  Index	  SelecFvity	  SQL>	  SELECT	  *	  FROM	  big_dwh_table	  WHERE	  album_id	  IS	  NOT	  NULL	  ORDER	  B...
5.	  100%	  Index	  SelecFvity	  SQL>	  SELECT	  *	  FROM	  big_dwh_table_2	  WHERE	  album_id	  IS	  NOT	  NULL	  ORDER	 ...
5.	  100%	  Index	  SelecFvity	  SQL>	  SELECT	  /*+	  index(a)	  */	  *	  from	  big_dwh_table_2	  a	  WHERE	  album_id	 ...
5.	  100%	  Index	  SelecFvity	  SQL>	  SELECT	  *	  from	  big_dwh_table_2	  WHERE	  album_id	  BETWEEN	  1	  AND	  15	  ...
5.	  100%	  Index	  SelecFvity	  SQL>	  SELECT	  *	  from	  big_dwh_table_2	  WHERE	  album_id	  BETWEEN	  1	  AND	  13	  ...
6.	  BLEVEL	  1	  =>	  BLEVEL	  2	  	  Careful	  of	  indexes	  increasing	  from	  BLEVEL	  1	  to	  2.	  Following	  dem...
6.	  BLEVEL	  1	  =>	  BLEVEL	  2	  	  SQL>	  select	  *	  from	  major_tom	  where	  id	  =	  42;	  	  	  Execution Plan-...
6.	  BLEVEL	  1	  =>	  BLEVEL	  2	  	  Let’s	  create	  another	  table,	  with	  a	  CODE	  column	  that’s	  has	  100	 ...
6.	  BLEVEL	  1	  =>	  BLEVEL	  2	  	  SQL>	  select	  *	  from	  ziggy	  z,	  major_tom	  m	  where	  z.id	  =	  m.id	  a...
6.	  BLEVEL	  1	  =>	  BLEVEL	  2	  	  Let’s	  just	  add	  another	  500	  rows	  (or	  0.15%	  of	  data)	  SQL>	  inser...
6.	  BLEVEL	  1	  =>	  BLEVEL	  2	  	  SQL>	  select	  *	  from	  major_tom	  where	  id	  =	  42;	  	  	  Execution Plan-...
6.	  BLEVEL	  1	  =>	  BLEVEL	  2	  	    SQL>	  select	  *	  from	  ziggy	  z,	  major_tom	  m	  where	  m.id	  =	  z.id	 ...
7.	  Why	  Unique	  Indexes	  Are	  Beyer	  •  Since	  Oracle8,	  Non-­‐Unique	  Indexes	  Can	  Police	     Primary	  and...
7.	  Why	  Unique	  Indexes	  Are	  Beyer	  SQL>	  CREATE	  TABLE	  index_size_test	  (id	  NUMBER,	  value	  VARCHAR2(100...
7.	  Why	  Unique	  Indexes	  Are	  Beyer	  row#0[8016]	  flag:	  -­‐-­‐-­‐-­‐-­‐-­‐,	  lock:	  2,	  len=20,	  data:(6):	  ...
7.	  Why	  Unique	  Indexes	  Are	  Beyer	  SQL>	  CREATE	  TABLE	  test1	  AS	  SELECT	  rownum	  id	  FROM	  dual	  CONN...
7.	  Why	  Unique	  Indexes	  Are	  Beyer	  SQL>	  SELECT	  index_name,	  blevel,	  leaf_blocks,	  num_rows	  	  	  	  	  ...
7.	  Why	  Unique	  Indexes	  Are	  Beyer	  Unique	  indexes	  have	  less	  latching	  and	  CPU	  related	  overheads	  ...
7.	  Why	  Unique	  Indexes	  Are	  Beyer	  In	  one	  session,	  run	  the	  following	  a	  couple	  of	  Fmes	  to	  en...
7.	  Why	  Unique	  Indexes	  Are	  Beyer	   NAME	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	...
7.	  Why	  Unique	  Indexes	  Are	  Beyer	  Now	  the	  same	  test	  but	  this	  Fme	  with	  a	  non-­‐unique	  index	 ...
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf
Upcoming SlideShare
Loading in …5
×

Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf

1,240 views

Published on

Published in: Technology, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,240
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
51
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Database & Technology 2 _ Richard Foote _ 10 things you probably dont know about Oracle's indexes.pdf

  1. 1. 10  Things  You  Might  Not  Know   About  Oracle  Indexes   Richard  Foote   The most comprehensive Oracle applications & technology content under one roof
  2. 2. Richard  Foote  •  Working  in  IT  for  25  years  (scary  stuff)  •  Working  with  Oracle  for  15  years  (almost  as  scary)  •  Previously  employed  by  Oracle  CorporaFon  for  5  ½  years  (scary  as  hell)  •  Currently  employed  by  the  Australian  Federal  Government  as  a  Senior   DBA  •  Responsible  for  many  large  scale,  mission  criFcal,  “life-­‐dependant”   classified  Oracle  systems  •  Based  in  sunny  Canberra,  Australia  •  Oracle  OakTable  member  since  2002  and  Oracle  ACE  Director  since  2008  •  Interests  includes  all  sports  and  music  (cool  stuff  like  David  Bowie,  Pink   Floyd,  Radiohead  and  Muse)  •  richard.foote@bigpond.com  •  Richard  Foote’s  Oracle  Blog:  hBp://richardfoote.wordpress.com/   The most comprehensive Oracle applications & technology content under one roof
  3. 3. 1.  Delete  More  Rows  To  Reduce   Deleted  Space  Within  An  Index  •  Very  common  advice  to  rebuild  index  if  percentage   of  deleted  space  >  20%  •  For  example  -­‐  Metalink  Note:  122008.1   recommended  this  for  many  years  •  Validate  index  structure  (Ignoring  that  it’s   expensive  and  locks  the  table)  •  Claimed  rebuild  will  remove  index  “deadwood”  and   make  index  more  efficient  •  However,  if  only  we  just  deleted  even  more  rows  ...   The most comprehensive Oracle applications & technology content under one roof
  4. 4. 1:  If  deleted  space  >20%,  delete  some  more!!  SQL>  create  table  radiohead  (id  number,  name  varchar2(20));  Table  created.      SQL>  insert  into  radiohead  select  rownum,  OK  COMPUTER  from  dual  connect  by  level  <=  100000;  100000  rows  created.      SQL>  commit;  Commit  complete.      SQL>  create  index  radiohead_i  on  radiohead(id)  pckree  0;  Index  created.      SQL>  analyze  index  radiohead_i  validate  structure;  Index  analyzed.      SQL>  select  lf_rows,  del_lf_rows,  round((del_lf_rows/lf_rows)*100)  PCT_DEL,  pct_used  from  index_stats;         LF_ROWS DEL_LF_ROWS    PCT_DEL   PCT_USED---------- ----------- ---------- ----------    100000           0          0        100 The most comprehensive Oracle applications & technology content under one roof
  5. 5. 1:  If  deleted  space  >20%,  delete  some  more!!  SQL>  delete  radiohead  where  mod(id,10)  IN  (2,4,6);  30000  rows  deleted.      SQL>  commit;  Commit  complete.    SQL>  analyze  index  radiohead_i  validate  structure;  Index  analyzed.      SQL>  select  lf_rows,  del_lf_rows,  (del_lf_rows/lf_rows)*100  PCT_DEL,  pct_used  from  index_stats;          LF_ROWS DEL_LF_ROWS    PCT_DEL   PCT_USED---------- ----------- ---------- ----------    100000       30000         30        100So  based  on  common  rebuild  criteria,  this  index  really  should  be  rebuilt  ...   The most comprehensive Oracle applications & technology content under one roof
  6. 6. 1:  If  deleted  space  >20%,  delete  some  more!!  Well,  let’s  just  delete  some  more  rows  ...  SQL>  delete  radiohead  where  mod(id,10)  =  8;    10000  rows  deleted.      SQL>  commit;  Commit  complete.      SQL>  analyze  index  radiohead_i  validate  structure;  Index  analyzed.      SQL>  select  lf_rows,  del_lf_rows,  round((del_lf_rows/lf_rows)*100)  PCT_DEL,  pct_used  from  index_stats;         LF_ROWS DEL_LF_ROWS    PCT_DEL   PCT_USED---------- ----------- ---------- ----------     70000       10000         14         70 The most comprehensive Oracle applications & technology content under one roof
  7. 7. 1:  If  deleted  space  >20%,  delete  some  more!!  •  What  many  don’t  realise  is  that  in  most  scenarios,   deleted  space  is  the  same  as  free  space  •  It  will  generally  eventually  get  reused  •  To  clean  out  deleted  space,  it  just  takes  the  leaf   block  to  be  modified  by  a  subsequent  transacFon  •  The  criteria  actually  rebuilds  indexes  that  don’t  need   rebuilding,  and  •  The  criteria  misses  out  on  those  indexes  that  might   actually  need  rebuilding   The most comprehensive Oracle applications & technology content under one roof
  8. 8. 2.Bitmap  Index  High  Cardinality  Columns    •  Very  common  advice  to  only  use  Bitmap  Index  with   “Low”  Cardinality  Columns  •  Generally  columns  with  less  than  20  disFnct  values  •  Examples:  Eye/Hair  Colour,  Sex,  States  of  Australia...  •  A  column  with  say  10,000  disFnct  values  would  be  far   too  many  and  result  in  huge,  inefficient  index    •  A  column  on  say  person  first  name  or  surname  would   be  totally  unsuitable  for  a  Bitmap  Index  •  But  would  it  really  ...   The most comprehensive Oracle applications & technology content under one roof
  9. 9. 2.Bitmap  Index  High  Cardinality  Columns    SQL>  CREATE  TABLE  big_dwh_table  (id  NUMBER,  album_id  NUMBER,  arFst_id  NUMBER,  country_id  NUMBER,                                                                                                                                        format_id  NUMBER,  release_date  DATE,  total_sales  NUMBER);  Table  created.    SQL>  CREATE  SEQUENCE  dwh_seq;  Sequence  created.    SQL>  create  or  replace  procedure  pop_big_dwh_table  as      2    v_id                    number;      3    v_arFst_id      number;      4    begin      5        for  v_album_id  in  1..10000  loop      6                v_arFst_id:=  ceil(dbms_random.value(0,100));      7                for  v_country_id  in  1..100  loop      8                    select  dwh_seq.nextval  into  v_id  from  dual;      9                    insert  into  big_dwh_table  values  (v_id,  v_album_id,  v_arFst_id,  vcountry_id,  ceil(dbms_random.value(0,4)),                                                                      trunc(sysdate-­‐mod(v_id,ceil(dbms_random.value(0,1000)))),  ceil(dbms_random.value(0,500000)));    10              end  loop;    11        end  loop;    12  commit;    13  end;    14  /  Procedure  created.    SQL>  exec  pop_big_dwh_table  PL/SQL  procedure  successfully  completed.   The most comprehensive Oracle applications & technology content under one roof
  10. 10. 2.Bitmap  Index  High  Cardinality  Columns     OK,  let’s  start  with  a  B-­‐Tree  Index  SQL>  CREATE  INDEX  big_dwh_album_id_i  ON  big_dwh_table(album_id)                        COMPUTE  STATISTICS;    Index  created.    SQL>  SELECT  i.index_type,  i.disFnct_keys,  t.num_rows  "T  ROWS",  t.blocks  "T  BLOCKS",                                                  i.num_rows  "I  ROWS",  i.clustering_factor  CF,  i.leaf_blocks                        FROM  user_indexes  i,  user_tables  t                        WHERE  i.table_name=t.table_name  and  i.index_name  =  BIG_DWH_ALBUM_ID_I;    INDEX_TYPE DISTINCT_KEYS T ROWS T BLOCKS I ROWS CF LEAF_BLOCKS---------- ------------- ---------- ---------- ---------- ---------- -----------NORMAL 10000 1000000 4948 1000000 4951 2090Note  the  album_id  column  has  a  relaFvely  “high”  cardinality  at  10,000  disFnct  values.  Also  note  the  B-­‐Tree  Index  is  extremely  well  clustered  (CF  matches  blocks  in  table)  and  has  2090  leaf  blocks  ...     The most comprehensive Oracle applications & technology content under one roof
  11. 11. 2.  Bitmap  Index  High  Cardinality  Columns    SQL>  SELECT  *  FROM  big_dwh_table  WHERE  album_id  =  42;    100 rows selected.Execution Plan-------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |Cost (%CPU)| Time |-------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 100 | 3000 | 103 (0)|00:00:02|| 1 | TABLE ACCESS BY INDEX ROWID| BIG_DWH_TABLE_2 | 100 | 3000 | 103 (0)|00:00:02||* 2 | INDEX RANGE SCAN | BIG_DWH_2_ALBUM_ID_I | 100 | | 3 (0)|00:00:01|-------------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 19 consistent gets 100 rows processed Note:  As  expected,  the  index  is  used  to  retrieve  the  relaFvely  few   100  rows  (0.01%  of  data).       Just  19  consistent  reads  required  ...   The most comprehensive Oracle applications & technology content under one roof
  12. 12. 2.Bitmap  Index  High  Cardinality  Columns    Let’s  create  same  index  as  a  Bitmap  Index.  However,  with  10,000  disFnct  values,  unlikely  to  be  efficient,  right  ?  SQL>  DROP  INDEX  big_dwh_album_id_i;    Index  dropped.    SQL>  CREATE  BITMAP  INDEX  big_dwh_album_id_i  ON  big_dwh_table(album_id);    Index  created.    SQL>  SELECT  index_name,  index_type,  disFnct_keys,  num_rows,  leaf_blocks,  blocks                        FROM  user_indexes  i,  user_segments  s                        WHERE  i.index_name  =  s.segment_name  and  i.index_name  =  BIG_DWH_ALBUM_ID_I;    INDEX_NAME INDEX_TYPE DISTINCT_KEYS NUM_ROWS LEAF_BLOCKS BLOCKS------------------ ---------- ------------- -------- ----------- ------BIG_DWH_ALBUM_ID_I BITMAP 10000 10000 56 128Wrong.  The  number  of  index  rows  is  just  10000,  one  for  each  disFnct  value  and  leaf  blocks  has  dropped  from  2090  to  just  56  !!   The most comprehensive Oracle applications & technology content under one roof
  13. 13. 2.  Bitmap  Index  High  Cardinality  Columns    SQL>  SELECT  *  FROM  big_dwh_table  WHERE  album_id  =  42;    100 rows selected.Execution Plan-------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 100 | 3000 | 22 (0)|00:00:01|| 1 | TABLE ACCESS BY INDEX ROWID | BIG_DWH_TABLE | 100 | 3000 | 22 (0)|00:00:01|| 2 | BITMAP CONVERSION TO ROWIDS| | | | | ||* 3 | BITMAP INDEX SINGLE VALUE | BIG_DWH_ALBUM_ID_I | | | | |-------------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 11 consistent gets 100 rows processed Note:  Not  only  is  the  index  used,  but  the  number  of  consistent  reads   has  dropped  from  19  to  just  11  !!   The most comprehensive Oracle applications & technology content under one roof
  14. 14. 2.  Bitmap  Index  High  Cardinality  Columns    The  Clustering  Factor  of  an  index  has  a  big  impact  on  the  overall  size  of  a  Bitmap  Index    This  is  due  to  having  more  conFnuous  zeros  in  the  bitmap  string  that  can  be  more  efficiently  compressed    SQL>  SELECT  i.index_name,  i.index_type,  t.num_rows  "TABLE  ROWS",  t.blocks,                                                  i.num_rows  "INDEX  ROWS",  i.clustering_factor  CF,  i.leaf_blocks                      FROM  user_indexes  i,  user_tables  t                        WHERE  i.table_name=t.table_name  and  i.index_name  =  BIG_DWH_ALBUM_ID_I;    INDEX_NAME INDEX_TYPE TABLE ROWS BLOCKS INDEX ROWS CF LEAF_BLOCKS------------------ ---------- ---------- ------- ---------- ------ -----------BIG_DWH_ALBUM_ID_I BITMAP 1000000 4948 10000 10000 56Note  the  CF  as  recorded  for  Bitmap  Indexes  is  a  liyle  meaningless  as  a  specific  index  entry  covers  many  Rowids  but  the  CF  calculaFon  is  sFll  based  on  the  block  within  the  rowid  changing  from  one  index  entry  to  the  next.    Therefore,  CF  of  an  index  is  commonly  recorded  as  being  the  number  of  index  row  entries   The most comprehensive Oracle applications & technology content under one roof
  15. 15. 2.  Bitmap  Index  High  Cardinality  Columns    Create  a  copy  of  the  table  but  this  Fme  clustered  by  the  TOTAL_SALES  column    Then  create  a  Bitmap  Index  on  the  now  poorly  clustered  ALBUM_ID  column  SQL>  CREATE  TABLE  big_dwh_table_2  AS  SELECT  *  FROM  big_dwh_table                        ORDER  BY  total_sales;    Table  created.    SQL>  CREATE  BITMAP  INDEX  big_dwh_2_album_id_i  ON  big_dwh_table_2(album_id);    Index  created.    SQL>  exec  dbms_stats.gather_table_stats(ownname=>null,  tabname=>  BIG_DWH_TABLE_2,  esFmate_percent=>  null,  cascade=>  true,  method_opt=>  FOR  ALL  COLUMNS  SIZE  1);    PL/SQL  procedure  successfully  completed.   The most comprehensive Oracle applications & technology content under one roof
  16. 16. 2.  Bitmap  Index  High  Cardinality  Columns    SQL>  SELECT  i.index_name,  i.index_type,  t.num_rows  "TABLE  ROWS",  t.blocks,                                                  i.num_rows  "INDEX  ROWS",  i.clustering_factor  CF,  i.leaf_blocks                        FROM  user_indexes  i,  user_tables  t                        WHERE  i.table_name=t.table_name  and  i.index_name  =  BIG_DWH_2_ALBUM_ID_I;    INDEX_NAME INDEX_TYPE TABLE ROWS BLOCKS INDEX ROWS CF LEAF_BLOCKS-------------------- ---------- ---------- ------- ---------- ------ -----------BIG_DWH_2_ALBUM_ID_I BITMAP 1000000 4973 10000 10000 455 Note:  Leaf  Blocks  has  jumped  up  significantly  from  56  blocks  to  455   blocks     The most comprehensive Oracle applications & technology content under one roof
  17. 17. 2.  Bitmap  Index  High  Cardinality  Columns    SQL>  SELECT  *  FROM  big_dwh_table_2  WHERE  album_id  =  42;    100 rows selected.Execution Plan-------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |Cost (%CPU)|Time |-------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 100| 3000 | 22 (0)|00:00:01|| 1 | TABLE ACCESS BY INDEX ROWID | BIG_DWH_TABLE_2 | 100| 3000 | 22 (0)|00:00:01|| 2 | BITMAP CONVERSION TO ROWIDS| | | | | ||* 3 | BITMAP INDEX SINGLE VALUE | BIG_DWH_2_ALBUM_ID_I | | | | |-------------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 101 consistent gets 100 rows processed Note:  The  number  of  consistent  reads  has  now  jumped  up  from  11  to   101  ...   The most comprehensive Oracle applications & technology content under one roof
  18. 18. 2.  Bitmap  Index  High  Cardinality  Columns     Of  course,  this  will  also  impact  Clustering  Factor  of  a  B-­‐Tree  Index  ...  SQL>  DROP  INDEX  big_dwh_2_album_id_i;    Index  dropped.    SQL>  CREATE  INDEX  big_dwh_2_album_id_i  ON  big_dwh_table_2(album_id);    Index  created.    SQL>  SELECT  i.index_name,  i.index_type,  t.num_rows  "TABLE  ROWS",  t.blocks,                                                  i.num_rows  "INDEX  ROWS",  i.clustering_factor  CF,  i.leaf_blocks                        FROM  user_indexes  i,  user_tables  t                        WHERE  i.table_name=t.table_name  and  i.index_name  =  BIG_DWH_2_ALBUM_ID_I;    INDEX_NAME INDEX_TYPE TABLE ROWS BLOCKS INDEX ROWS CF LEAF_BLOCKS-------------------- ---------- ---------- ------- ---------- ------- -----------BIG_DWH_2_ALBUM_ID_I NORMAL 1000000 4973 1000000 990003 2090 Although  the  index  has  same  no.  of  leaf  blocks,  the  Clustering  Factor   has  jumped  to  a  massive  990003  ...   The most comprehensive Oracle applications & technology content under one roof
  19. 19. 2.  Bitmap  Index  High  Cardinality  Columns    SQL>  SELECT  *  FROM  big_dwh_table_2  WHERE  album_id  =  42;    100 rows selected.Execution Plan-------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |Cost (%CPU)| Time |-------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 100 | 3000 | 103 (0)|00:00:02|| 1 | TABLE ACCESS BY INDEX ROWID| BIG_DWH_TABLE_2 | 100 | 3000 | 103 (0)|00:00:02||* 2 | INDEX RANGE SCAN | BIG_DWH_2_ALBUM_ID_I | 100 | | 3 (0)|00:00:01|-------------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 109 consistent gets 100 rows processed Consistent  reads  has  jumped  from  19  to  109  which  is  sFll  worse  than   the  101  consistent  reads    of  the  Bitmap  Index  ...   The most comprehensive Oracle applications & technology content under one roof
  20. 20. 2.  Bitmap  Index  High  Cardinality  Columns    Table  containing  person  names,  using  freshly  rebuilt  B-­‐Tree  Indexes  ...   NAME INDEX_TYPE NUM_ROWS DISTINCT_KEYS LEAF_BLOCKS ---------- ------------ ---------- ------------- ----------- FIRST NAME NORMAL 2378672 147446 5842 LAST NAME NORMAL 2405599 361177 6202     SQL>  select  *  from  persons  where  given_name1  =  DAVID  or  last_name  =  BOWIE;   39240  rows  selected.       Execution Plan --------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 174 | 36888 | 164 (0)| 00:00:01 | | 1 | CONCATENATION | | | | | | | 2 | TABLE ACCESS BY INDEX ROWID| PERSONS | 47 | 9964 | 44 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | PERS_LAST_NAME_I | 47 | | 3 (0)| 00:00:01 | |* 4 | TABLE ACCESS BY INDEX ROWID| PERSONS | 127 | 26924 | 120 (0)| 00:00:01 | |* 5 | INDEX RANGE SCAN | PERS_FIRST_NAME1_I | 127 | | 3 (0)| 00:00:01 | --------------------------------------------------------------------------------------------------- Statistics ---------------------------------------------------------- 28600 consistent gets The most comprehensive Oracle applications & technology content under one roof
  21. 21. 2.  Bitmap  Index  High  Cardinality  Columns    Bitmap  Indexes  are  actually  substanFally  smaller  and  more  efficient  ...  NAME INDEX_TYPE NUM_ROWS DISTINCT_KEYS LEAF_BLOCKS---------- ------------ ---------- ------------- -----------FIRST NAME BITMAP 148208 147463 1608 (-4234)LAST NAME BITMAP 361421 361183 2543 (-3659)    SQL>  select  *  from  persons  where  given_name1  =  DAVID  or  last_name  =  BOWIE;    39240  rows  selected.      Execution Plan---------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 176 | 37312 | 43 (0)| 00:00:01 || 1 | TABLE ACCESS BY INDEX ROWID | PERSONS | 176 | 37312 | 43 (0)| 00:00:01 || 2 | BITMAP CONVERSION TO ROWIDS| | | | | || 3 | BITMAP OR | | | | | ||* 4 | BITMAP INDEX SINGLE VALUE| PERS_FIRST_NAME1_I | | | | ||* 5 | BITMAP INDEX SINGLE VALUE| PERS_LAST_NAME_I | | | | |---------------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 28483 consistent gets The most comprehensive Oracle applications & technology content under one roof
  22. 22. 2.  Bitmap  Index  High  Cardinality  Columns    •  If  you  only  use  Bitmap  Indexes  for  low  cardinality   columns,  you’re  not  taking  full  advantage  of  them  •  Suitable  for  all  columns  that  are  not  approaching   uniqueness  •  BUT,  only  for  Data  Warehouse  environments  due  to   locking  implicaFons  of  concurrent  transacFons   within  same  table   The most comprehensive Oracle applications & technology content under one roof
  23. 23. 3.  B-­‐Tree  Index  Low  Cardinality  Columns  •  Generally  B-­‐Tree  Indexes  more  suitable  for  columns   with  many  disFnct  values  •  Increases  selecFvity  and  makes  indexes  a  more   efficient  opFon  to  the  CBO  •  However,  there  are  always  excepFons  •  B-­‐Tree  Index  might  be  the  perfect  candidate  for  a   column  with  as  low  as  1  disFnct  value  ...   The most comprehensive Oracle applications & technology content under one roof
  24. 24. 3.  B-­‐Tree  Index  Low  Cardinality  Columns   SQL>  create  table  bowie  (id  number,  code  number,  name  varchar2(50));   Table  created.       SQL>  create  index  bowie_code_i  on  bowie(code);   Index  created.     SQL>  insert  into  bowie  select  rownum,  null,  Ziggy  Stardust  and  the  Spiders  From  Mars  from  dual   connect  by  level  <=  1000000;   1000000  rows  created.       SQL>  update  bowie  set  code  =  42  where  mod(id,10000)  =  0;   100  rows  updated.       SQL>  commit;   Commit  complete.     SQL>  exec  dbms_stats.gather_table_stats(ownname=>null,  tabname=>BOWIE,  cascade=>  true,   esFmate_percent=>null,  method_opt=>FOR  ALL  COLUMNS  SIZE  1);       PL/SQL  procedure  successfully  completed.  CODE  column  only  has  1  disFnct  value  although  most  rows  are  NULL  ...   The most comprehensive Oracle applications & technology content under one roof
  25. 25. 3.  B-­‐Tree  Index  Low  Cardinality  Columns  SQL>  select  blevel,  leaf_blocks,  disFnct_keys  from  dba_indexes  where  index_name=BOWIE_CODE_I;       BLEVEL LEAF_BLOCKS DISTINCT_KEYS---------- ----------- ------------- 0 1 1  SQL>  select  column_name,  num_disFnct,  num_nulls  from  dba_tab_columns  where  table_name  =  BOWIE  and  column_name  =  CODE;      COLUMN_NAME NUM_DISTINCT NUM_NULLS------------ ------------ ----------CODE 1 999900    As  NULLs  are  not  stored  in  B-­‐Tree  Indexes  by  default,  index  is  Fny    CBO  knows  there’s  only  1  disFnct  value  but  it  also  knows  most  rows  are  only  NULLs   The most comprehensive Oracle applications & technology content under one roof
  26. 26. 3.  B-­‐Tree  Index  Low  Cardinality  Columns  SQL>  select  *  from  bowie  where  code  =  42;      100  rows  selected.      Execution Plan--------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |--------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 100 | 4700 | 101 (0)| 00:00:02 || 1 | TABLE ACCESS BY INDEX ROWID| BOWIE | 100 | 4700 | 101 (0)| 00:00:02 ||* 2 | INDEX RANGE SCAN | BOWIE_CODE_I | 100 | | 1 (0)| 00:00:01 |--------------------------------------------------------------------------------------------CBO  will  happily  use  index  on  CODE  column  with  1  disFnct  value    No  histograms  necessary  as  exisFng  staFsFcs  sufficient  for  CBO  to  know  index  is  the  most  efficient  access  path  ...   The most comprehensive Oracle applications & technology content under one roof
  27. 27. 4.  Index  Just  Which  Column  Values  You   Want  •  By  default,  all  values  within  a  column  are  indexed  •  There  are  many  scenarios  when  you  may  not  want   to  index  all  values  within  a  column  •  Some  column  values  maybe  too  numerous  to  be  of   pracFcal  use  within  the  index  •  Some  column  values  may  unnecessarily  inflate  size   and  efficiency  of  index  •  So,  just  dont  index  them  ...   The most comprehensive Oracle applications & technology content under one roof
  28. 28. 4.  Just  index  some  column  values  SQL>  CREATE  TABLE  index_some_stuff  (id  number,  status  varchar2(20),  descripFon  varchar2(50));    Table  created.      SQL>  INSERT  INTO  index_some_stuff  SELECT  rownum,  PROCESSED,  NOT  REALLY  INTERESTED  WITH  THIS  ROW  FROM  DUAL  CONNECT  BY  LEVEL  <=  1000000;    1000000  rows  created.      SQL>  UPDATE  index_some_stuff  SET  status  =  BOWIE,  descripFon  =  ROW  OF  INTEREST  where  mod(id,10000)=42;    100  rows  updated.      SQL>  commit;    Commit  complete.      SQL>  SELECT  status,  count(*)  FROM  index_some_stuff  GROUP  BY  status;      STATUS                 COUNT(*)-------------------- ----------PROCESSED                999900BOWIE                       100 The most comprehensive Oracle applications & technology content under one roof
  29. 29. 4.  Just  index  some  column  values  SQL>  CREATE  INDEX  index_some_stuff_i_1  ON  index_some_stuff(status);  Index  created.    SQL>  exec  dbms_stats.gather_table_stats(ownname=>BOWIE,  tabname=>  ’INDEX_SOME_STUFF,  method_opt=>  FOR  COLUMNS  STATUS  SIZE  5);    PL/SQL  procedure  successfully  completed.    SQL>  SELECT  *  FROM  index_some_stuff  WHERE  status  =  BOWIE;      100  rows  selected.      Execution Plan----------------------------------------------------------------------------------------------------| Id  | Operation                   | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |----------------------------------------------------------------------------------------------------|   0 | SELECT STATEMENT            |                      |   100 |  5200 |     4   (0)| 00:00:01 ||   1 |  TABLE ACCESS BY INDEX ROWID| INDEX_SOME_STUFF     |   100 |  5200 |     4   (0)| 00:00:01 ||*  2 |   INDEX RANGE SCAN          | INDEX_SOME_STUFF_I_1 |   100 |       |     3   (0)| 00:00:01 |----------------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 104 consistent gets 100 rows processed The most comprehensive Oracle applications & technology content under one roof
  30. 30. 4.  Just  index  some  column  values  But  why  bother  indexing  all  the  common  values  when  they’ll  never  be  referenced  ?  SQL>  CREATE  INDEX  index_some_stuff_i_2  ON    index_some_stuff(DECODE(status,  BOWIE,  BOWIE,  NULL))  COMPUTE  STATISTICS;  Index  created.    SQL>  exec  dbms_stats.gather_table_stats(ownname=>BOWIE,  tabname=>  ‘INDEX_SOME_STUFF,  method_opt=>FOR  ALL  HIDDEN  COLUMNS  SIZE  1,  cascade=>  true);  PL/SQL  procedure  successfully  completed.    SQL>  SELECT  index_name,  blevel,  leaf_blocks,  disFnct_keys,  num_rows    FROM  dba_indexes  WHERE  owner=BOWIE  AND  table_name=INDEX_SOME_STUFF;    INDEX_NAME BLEVEL LEAF_BLOCKS DISTINCT_KEYS NUM_ROWS------------------------------ ---------- ----------- ------------- ----------INDEX_SOME_STUFF_I_2 0 1 1 100INDEX_SOME_STUFF_I_1 2 2924 2 1000000 The  index  is  only  a  fracFon  the  size  of  the  previous  index  as  it  only  contains  the   one  index  entry  of  interest   The most comprehensive Oracle applications & technology content under one roof
  31. 31. 4.  Just  index  some  column  values  SQL>  SELECT  *  FROM  bowie.index_some_stuff                        WHERE(DECODE(status,  BOWIE,  BOWIE,  null))  =  BOWIE;    100 row selected.----------------------------------------------------------------------------------------------------| Id  | Operation                   | Name                 | Rows  | Bytes | Cost (%CPU)| Time     |----------------------------------------------------------------------------------------------------|   0 | SELECT STATEMENT            |                      |   100 |  5300 |   101   (0)| 00:00:02 ||   1 |  TABLE ACCESS BY INDEX ROWID| INDEX_SOME_STUFF     |   100 |  5300 |   101   (0)| 00:00:02 ||*  2 |   INDEX RANGE SCAN          | INDEX_SOME_STUFF_I_2 |   100 |       |     1   (0)| 00:00:01 |----------------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 102 consistent gets 100 rows processed Note:  consistent  gets  have  now  reduced  down  from  104  to  102   The most comprehensive Oracle applications & technology content under one roof
  32. 32. 4.  Just  index  some  column  values  Can  use  zero  sized  unusable  indexes  to  your  advantage  to  index  only  useful  porFons  of  a  table.  Most  data  here  is  processed:  SQL>  create  table  bowie_stuff  (id  number,  processed  varchar2(10));  Table  created.    SQL>  insert  into  bowie_stuff  select  rownum,  YES  from  dual  connect  by  level  <=  1000000;  1000000  rows  created.    SQL>  commit;  Commit  complete.    SQL>  update  bowie_stuff  set  processed  =  ‘NO’  where  id  in  (999990,  999992,  999994,  999996,  999998);  5  rows  updated.    SQL>  commit;  Commit  complete.    SQL>  create  index  bowie_stuff_i  on  bowie_stuff(processed)  pckree  0;  Index  created. The most comprehensive Oracle applications & technology content under one roof
  33. 33. 4.  Just  index  some  column  values  SQL>  select  index_name,  leaf_blocks  from  dba_indexes  where  index_name  =  BOWIE_STUFF_I;    INDEX_NAME LEAF_BLOCKS------------------------------ -----------BOWIE_STUFF_I 1877  SQL>  select  segment_name,  blocks  from  dba_segments  where  segment_name  =  BOWIE_STUFF_I;    SEGMENT_NAME BLOCKS-------------------- ----------BOWIE_STUFF_I 1920  SQL>  exec  dbms_stats.gather_table_stats(ownname=>BOWIE,  tabname=>BOWIE_STUFF,  esFmate_percent=>null,  cascade=>  true,  method_opt=>  FOR  ALL  COLUMNS  SIZE  1);    PL/SQL  procedure  successfully  completed.    SQL>  exec  dbms_stats.gather_table_stats(ownname=>BOWIE,  tabname=>BOWIE_STUFF,  esFmate_percent=>null,  method_opt=>  FOR  COLUMNS  PROCESSED  SIZE  5);    PL/SQL  procedure  successfully  completed. The most comprehensive Oracle applications & technology content under one roof
  34. 34. 4.  Just  index  some  column  values  SQL>  select  *  from  bowie_stuff  where  processed  =  NO;    Execution Plan---------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |---------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 5 | 40 | 4 (0)| 00:00:01 || 1 | TABLE ACCESS BY INDEX ROWID| BOWIE_STUFF | 5 | 40 | 4 (0)| 00:00:01 ||* 2 | INDEX RANGE SCAN | BOWIE_STUFF_I | 5 | | 3 (0)| 00:00:01 |---------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 0 recursive calls 0 db block gets 6 consistent gets 0 physical reads 0 redo size 540 bytes sent via SQL*Net to client 396 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 5 rows processed The most comprehensive Oracle applications & technology content under one roof
  35. 35. 4.  Just  index  some  column  values  However  in  11g  R2,  if  we  now  recreate  the  index  as  a  parFFoned  index  with  only  the  “useful”  porFon  of  the  index  usable  ...  SQL>  drop  index  bowie_stuff_i;    Index  dropped.    SQL>  create  index  bowie_stuff_i  on  bowie_stuff(processed)      2    global  parFFon  by  range  (processed)      3    (parFFon  not_processed_part  values  less  than  (YES),      4      parFFon  processed_part  values  less  than  (MAXVALUE))      5    unusable;    Index  created.    SQL>  alter  index  bowie_stuff_i  rebuild  parFFon  not_processed_part;    Index  altered. The most comprehensive Oracle applications & technology content under one roof
  36. 36. 4.  Just  index  some  column  values  We  now  only  use  a  fracFon  of  the  storage  for  the  index  and  the  “useful”  porFon  of  the  indexed  data  is  just  a  single  leaf  block  in  size  ...  SQL>  select  index_name,  parFFon_name,  leaf_blocks  from  dba_ind_parFFons  where  index_name  =  BOWIE_STUFF_I;    INDEX_NAME PARTITION_NAME LEAF_BLOCKS-------------------- -------------------- -----------BOWIE_STUFF_I PROCESSED_PART 0BOWIE_STUFF_I NOT_PROCESSED_PART 1  SQL>  select  segment_name,  parFFon_name,  blocks  from  dba_segments  where  segment_name  =  BOWIE_STUFF_I;    SEGMENT_NAME PARTITION_NAME BLOCKS-------------------- -------------------- ----------BOWIE_STUFF_I NOT_PROCESSED_PART 8 The most comprehensive Oracle applications & technology content under one roof
  37. 37. 4.  Just  index  some  column  values  SQL>  select  *  from  bowie_stuff  where  processed  =  NO;    Execution Plan--------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |--------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 5 | 45 | 1 (0)| 00:00:01 | | || 1 | PARTITION RANGE SINGLE | | 5 | 45 | 1 (0)| 00:00:01 | 1 | 1 || 2 | TABLE ACCESS BY INDEX ROWID| BOWIE_STUFF | 5 | 45 | 1 (0)| 00:00:01 | | ||* 3 | INDEX RANGE SCAN | BOWIE_STUFF_I | 5 | | 1 (0)| 00:00:01 | 1 | 1 |--------------------------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 0 recursive calls 0 db block gets 4 consistent gets 0 physical reads 0 redo size 542 bytes sent via SQL*Net to client 395 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 5 rows processed Note:  The  query  itself  is  also  more  efficient  with  consistent  gets   reduced  from  6  down  to  4  ...   The most comprehensive Oracle applications & technology content under one roof
  38. 38. 5.  100%  Index  SelecFvity  •  Generally  indexes  only  process  a  “small”  %  of   overall  data  •  Cheaper  to  use  a  Full  Table  Scan  to  process  a   “high”  %  of  data  •  Common  belief  that  if  returning  more  than  ‘x’%,   indexes  are  ignored  by  CBO  •  However,  indexes  can  be  most  efficient  access   path  when  returning  anything  up  to  100%  of  data   The most comprehensive Oracle applications & technology content under one roof
  39. 39. 5.  100%  Index  SelecFvity  SQL>  create  table  ziggy  (id  number,  name  varchar2(30));  Table  created.      SQL>  insert  into  ziggy  select  rownum,  ZIGGY  STARDUST  from  dual  connect  by  level  <=  1000000;  1000000  rows  created.      SQL>  commit;  Commit  complete.      SQL>  delete  ziggy  where  id  between  1  and  999000;  999000  rows  deleted.      SQL>  commit;  Commit  complete.    SQL>  create  index  ziggy_id_i  on  ziggy(id);  Index  created.      SQL>  exec  dbms_stats.gather_table_stats(ownname=>BOWIE,  tabname=>ZIGGY,  cascade=>  true,  esFmate_percent=>null,  method_opt=>  FOR  ALL  COLUMNS  SIZE  1);   The most comprehensive Oracle applications & technology content under one roof
  40. 40. 5.  100%  Index  SelecFvity  SQL>  select  id  from  ziggy  where  id  >  1;      1000  rows  selected.      Execution Plan-----------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |-----------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1000 | 5000 | 3 (0)| 00:00:01 ||* 1 | INDEX FAST FULL SCAN| ZIGGY_ID_I | 1000 | 5000 | 3 (0)| 00:00:01 |-----------------------------------------------------------------------------------    If  all  columns  of  interest  can  be  found  within  an  index,  an  Index  Fast  Full  Scan  can  treat  the  index  as  a  “skinny”  table.   The most comprehensive Oracle applications & technology content under one roof
  41. 41. 5.  100%  Index  SelecFvity  SQL>  select  *  from  ziggy  where  id  >  1;      1000  rows  selected.      Execution Plan------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|Time |------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1000 | 20000 | 8 (0)|00:00:01 || 1 | TABLE ACCESS BY INDEX ROWID| ZIGGY | 1000 | 20000 | 8 (0)|00:00:01 ||* 2 | INDEX RANGE SCAN | ZIGGY_ID_I | 1000 | | 4 (0)|00:00:01 |------------------------------------------------------------------------------------------However,  because  the  table  is  so  fragmented,  the  CBO  is  using  the  index  to  access  the  table  and  retrieve  100%  of  the  rows  ...   The most comprehensive Oracle applications & technology content under one roof
  42. 42. 5.  100%  Index  SelecFvity  SQL>  CREATE  TABLE  big_dwh_table_2  AS  SELECT  *  FROM  big_dwh_table                        ORDER  BY  total_sales;    Table  created.    SQL>  CREATE  INDEX  big_dwh_album_id_i  ON  big_dwh_table(album_id);    Index  created.    SQL>  CREATE  INDEX  big_dwh_2_album_id_i  ON  big_dwh_table_2(album_id);    Index  created.    SQL>  SELECT  index_name,  leaf_blocks,  clustering_factor  FROM  user_indexes                        WHERE  index_name  like  BIG_DWH%ALBUM_ID_I;    INDEX_NAME LEAF_BLOCKS CLUSTERING_FACTOR------------------------------ ----------- -----------------BIG_DWH_2_ALBUM_ID_I 2090 990282BIG_DWH_ALBUM_ID_I 2090 4957 The most comprehensive Oracle applications & technology content under one roof
  43. 43. 5.  100%  Index  SelecFvity  SQL>  SELECT  *  FROM  big_dwh_table  WHERE  album_id  BETWEEN  10  AND  20  ORDER  BY  id;    1100  rows  selected.    Execution Plan----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows| Bytes |Cost(%CPU)| Time |----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | |1200 | 36000 | 12 (9)|00:00:01 || 1 | SORT ORDER BY | |1200 | 36000 | 12 (9)|00:00:01 || 2 | TABLE ACCESS BY INDEX ROWID| BIG_DWH_TABLE |1200 | 36000 | 11 (0)|00:00:01 ||* 3 | INDEX RANGE SCAN | BIG_DWH_ALBUM_ID_I |1200 | | 5 (0)|00:00:01 |----------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 1 recursive calls 0 db block gets 11 consistent gets 4 physical reads 0 redo size 30759 bytes sent via SQL*Net to client 396 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 1100 rows processed The most comprehensive Oracle applications & technology content under one roof
  44. 44. 5.  100%  Index  SelecFvity  SQL>  SELECT  *  FROM  big_dwh_table  WHERE  album_id  BETWEEN  10  AND  20                        ORDER  BY  album_id;    1100 rows selected.Execution Plan----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |Cost(%CPU)| Time |----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1200 | 36000 | 11 (0)|00:00:01|| 1 | TABLE ACCESS BY INDEX ROWID| BIG_DWH_TABLE | 1200 | 36000 | 11 (0)|00:00:01||* 2 | INDEX RANGE SCAN | BIG_DWH_ALBUM_ID_I | 1200 | | 5 (0)|00:00:01|----------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 1 recursive calls 0 db block gets 13 consistent gets 0 physical reads 0 redo size 30759 bytes sent via SQL*Net to client 396 bytes received via SQL*Net from client 2 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1100 rows processed The most comprehensive Oracle applications & technology content under one roof
  45. 45. 5.  100%  Index  SelecFvity  SQL>  SELECT  *  FROM  big_dwh_table  WHERE  album_id  BETWEEN  1  AND  10000                        ORDER  BY  album_id;    Execution Plan----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |Cost(%CPU)| Time |----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1000K| 28M|7145 (2)|00:00:48|| 1 | TABLE ACCESS BY INDEX ROWID| BIG_DWH_TABLE | 1000K| 28M|7145 (2)|00:00:48||* 2 | INDEX FULL SCAN | BIG_DWH_ALBUM_ID_I | 1000K| |2130 (2)|00:00:15|---------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 0 recursive calls 0 db block gets 139919 consistent gets 0 physical reads 0 redo size 37476458 bytes sent via SQL*Net to client 733722 bytes received via SQL*Net from client 66668 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1000000 rows processed The most comprehensive Oracle applications & technology content under one roof
  46. 46. 5.  100%  Index  SelecFvity  SQL>  SELECT  *  FROM  big_dwh_table  ORDER  BY  album_id;    1000000  rows  selected.    Execution Plan--------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |--------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1000K| 28M| | 7699 (4)| 00:00:51 || 1 | SORT ORDER BY | | 1000K| 28M| 91M| 7699 (4)| 00:00:51 || 2 | TABLE ACCESS FULL| BIG_DWH_TABLE | 1000K| 28M| | 555 (10)| 00:00:04 |--------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 43 recursive calls 5 db block gets 4954 consistent gets 5432 physical reads 0 redo size 37476485 bytes sent via SQL*Net to client 733722 bytes received via SQL*Net from client 66668 SQL*Net roundtrips to/from client 0 sorts (memory) 1 sorts (disk) 1000000 rows processed The most comprehensive Oracle applications & technology content under one roof
  47. 47. 5.  100%  Index  SelecFvity  SQL>  SELECT  *  FROM  big_dwh_table  WHERE  album_id  IS  NOT  NULL  ORDER  BY  album_id;    1000000 rows selected.Execution Plan----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |Cost(%CPU)| Time |----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1000K| 28M|7145 (2)|00:00:48|| 1 | TABLE ACCESS BY INDEX ROWID| BIG_DWH_TABLE | 1000K| 28M|7145 (2)|00:00:48||* 2 | INDEX FULL SCAN | BIG_DWH_ALBUM_ID_I | 1000K| |2130 (2)|00:00:15|----------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 0 recursive calls 0 db block gets 139919 consistent gets 7040 physical reads 0 redo size 37476493 bytes sent via SQL*Net to client 733722 bytes received via SQL*Net from client 66668 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1000000 rows processed The most comprehensive Oracle applications & technology content under one roof
  48. 48. 5.  100%  Index  SelecFvity  SQL>  SELECT  *  FROM  big_dwh_table_2  WHERE  album_id  IS  NOT  NULL  ORDER  BY  album_id;    1000000 rows selected.Execution Plan----------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |----------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1000K| 28M| | 7704 (4)| 00:00:51 || 1 | SORT ORDER BY | | 1000K| 28M| 91M| 7704 (4)| 00:00:51 ||* 2 | TABLE ACCESS FULL| BIG_DWH_TABLE_2 | 1000K| 28M| | 561 (11)| 00:00:04 |----------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 44 recursive calls 18 db block gets 4979 consistent gets 7669 physical reads 0 redo size 36721186 bytes sent via SQL*Net to client 733722 bytes received via SQL*Net from client 66668 SQL*Net roundtrips to/from client 0 sorts (memory) 1 sorts (disk) 1000000 rows processed The most comprehensive Oracle applications & technology content under one roof
  49. 49. 5.  100%  Index  SelecFvity  SQL>  SELECT  /*+  index(a)  */  *  from  big_dwh_table_2  a  WHERE  album_id  IS  NOT  NULL                        ORDER  BY  album_id;    1000000 rows selected.Execution Plan-------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |Cost (%CPU)|Time |-------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1000K| 28M| 993K (1)|01:49:31 || 1 | TABLE ACCESS BY INDEX ROWID| BIG_DWH_TABLE_2 | 1000K| 28M| 993K (1)|01:49:31 ||* 2 | INDEX FULL SCAN | BIG_DWH_2_ALBUM_ID_I | 1000K| | 2130 (2)|00:00:15 |-------------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 0 recursive calls 0 db block gets 1059553 consistent gets 7065 physical reads 0 redo size 36720213 bytes sent via SQL*Net to client 733722 bytes received via SQL*Net from client 66668 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1000000 rows processed The most comprehensive Oracle applications & technology content under one roof
  50. 50. 5.  100%  Index  SelecFvity  SQL>  SELECT  *  from  big_dwh_table_2  WHERE  album_id  BETWEEN  1  AND  15                        ORDER  BY  album_id;    1500 rows selected.Execution Plan------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost(%CPU)| Time |------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1500 | 45000 | 1297 (5)| 00:00:07|| 1 | SORT ORDER BY | | 1500 | 45000 | 1297 (5)| 00:00:07||* 2 | TABLE ACCESS FULL| BIG_DWH_TABLE_2 | 1500 | 45000 | 1296 (4)| 00:00:07|------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 0 recursive calls 0 db block gets 4981 consistent gets 0 physical reads 0 redo size 54139 bytes sent via SQL*Net to client 1485 bytes received via SQL*Net from client 101 SQL*Net roundtrips to/from client 1 sorts (memory) 0 sorts (disk) 1500 rows processed The most comprehensive Oracle applications & technology content under one roof
  51. 51. 5.  100%  Index  SelecFvity  SQL>  SELECT  *  from  big_dwh_table_2  WHERE  album_id  BETWEEN  1  AND  13                        ORDER  BY  album_id;    1300 rows selected.Execution Plan-------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |Cost(%CPU)| Time |-------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 1300| 39000 |1295 (1)| 00:00:07 || 1 | TABLE ACCESS BY INDEX ROWID| BIG_DWH_TABLE_2 | 1300| 39000 |1295 (1)| 00:00:07 ||* 2 | INDEX RANGE SCAN | BIG_DWH_2_ALBUM_ID_I | 1300| | 5 (0)| 00:00:01 |-------------------------------------------------------------------------------------------------Statistics---------------------------------------------------------- 0 recursive calls 0 db block gets 1385 consistent gets 60 physical reads 0 redo size 47048 bytes sent via SQL*Net to client 1342 bytes received via SQL*Net from client 88 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 1300 rows processed The most comprehensive Oracle applications & technology content under one roof
  52. 52. 6.  BLEVEL  1  =>  BLEVEL  2    Careful  of  indexes  increasing  from  BLEVEL  1  to  2.  Following  demo  11.2.0.1  with  8K  block  size.    SQL>  create  table  major_tom  (id  number,  code  number,  name  varchar2(30));    Table  created.      SQL>  create  index  major_tom_i  on  major_tom(id);    Index  created.      SQL>  insert  into  major_tom  select  rownum,  mod(rownum,100),  GROUND  CONTROL  from  dual  connect  by  level  <=336000;    336000  rows  created.        SQL>  exec  dbms_stats.gather_table_stats(ownname=>null,  tabname=>  MAJOR_TOM,  cascade=>  true,  esFmate_percent=>null,  method_opt=>FOR  ALL  COLUMNS  SIZE  1);    PL/SQL  procedure  successfully  completed.    SQL>  select  blevel,  leaf_blocks,  num_rows,  clustering_factor  from  dba_indexes  wh  ere  index_name=MAJOR_TOM_I;     BLEVEL LEAF_BLOCKS NUM_ROWS CLUSTERING_FACTOR---------- ----------- ---------- ----------------- 1 671 336000 1296   The most comprehensive Oracle applications & technology content under one roof
  53. 53. 6.  BLEVEL  1  =>  BLEVEL  2    SQL>  select  *  from  major_tom  where  id  =  42;      Execution Plan-------------------------------------------------------------------------------------------| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     |-------------------------------------------------------------------------------------------|   0 | SELECT STATEMENT            |             |     1 |    23 |     2   (0)| 00:00:01 ||   1 |  TABLE ACCESS BY INDEX ROWID| MAJOR_TOM   |     1 |    23 |     2   (0)| 00:00:01 ||*  2 |   INDEX RANGE SCAN          | MAJOR_TOM_I |     1 |       |     1   (0)| 00:00:01 |------------------------------------------------------------------------------------------- Statistics----------------------------------------------------------        0  recursive calls          0  db block gets          4  consistent gets          0  physical reads        0  redo size        531  bytes sent via SQL*Net to client        395  bytes received via SQL*Net from client          2  SQL*Net roundtrips to/from client          6  sorts (memory)          0  sorts (disk)          1  rows processed  When  BLEVEL  =  1,  CBO  ignores  the  BLEVEL  from  its  calculaFons   The most comprehensive Oracle applications & technology content under one roof
  54. 54. 6.  BLEVEL  1  =>  BLEVEL  2    Let’s  create  another  table,  with  a  CODE  column  that’s  has  100  occurrences  of  each  value  ...  SQL>  create  table  ziggy  (id  number,  code  number,  name  varchar2(30));    Table  created.      SQL>  insert  into  ziggy  select  rownum,  mod(rownum,10000),  ZIGGY  STARDUST  from  dual  connect  by  level  <=  1000000;    1000000  rows  created.    SQL>  commit;  Commit  complete.      SQL>  exec  dbms_stats.gather_table_stats(ownname=>null,  tabname=>  ZIGGY,  cascade=>  true,  esFmate_percent=>null,  method_opt=>FOR  ALL  COLUMNS  SIZE  1);    PL/SQL  procedure  successfully  completed.   The most comprehensive Oracle applications & technology content under one roof
  55. 55. 6.  BLEVEL  1  =>  BLEVEL  2    SQL>  select  *  from  ziggy  z,  major_tom  m  where  z.id  =  m.id  and  z.code  in  (42,  4242);      68  rows  selected.      Execution Plan--------------------------------------------------------------------------------------------| Id  | Operation                    | Name        | Rows  | Bytes | Cost (%CPU)| Time     |--------------------------------------------------------------------------------------------|   0 | SELECT STATEMENT             |             |   200 |  9400 |  1372   (2)| 00:00:17 ||   1 |  NESTED LOOPS                |             |       |       |            |          ||   2 |   NESTED LOOPS               |             |   200 |  9400 |  1372   (2)| 00:00:17 ||*  3 |    TABLE ACCESS FULL         | ZIGGY       |   200 |  4800 |  1105   (2)| 00:00:14 ||*  4 |    INDEX RANGE SCAN          | MAJOR_TOM_I |     1 |       |     1   (0)| 00:00:01 ||   5 |   TABLE ACCESS BY INDEX ROWID| MAJOR_TOM   |     1 |    23 |     2   (0)| 00:00:01 |--------------------------------------------------------------------------------------------CBO  choose  a  Nest  Loop  as  the  cost  of  accessing  the  MAJOR_TOM  table  100  Fmes  via  the  index  is  relaFvely  inexpensive   The most comprehensive Oracle applications & technology content under one roof
  56. 56. 6.  BLEVEL  1  =>  BLEVEL  2    Let’s  just  add  another  500  rows  (or  0.15%  of  data)  SQL>  insert  into  major_tom  select  rownum+336000,  mod(rownum,100),  GROUND  CONTROL  from  dual  connect  by  level  <=500;    500  rows  created.      SQL>  commit;    Commit  complete.      SQL>  exec  dbms_stats.gather_table_stats(ownname=>null,  tabname=>  MAJOR_TOM,  cascade=>  true,  esFmate_percent=>null,  method_opt=>FOR  ALL  COLUMNS  SIZE  1);    PL/SQL  procedure  successfully  completed.        SQL>  select  blevel,  leaf_blocks,  num_rows,  clustering_factor  from  dba_indexes  where  index_name  =  MAJOR_TOM_I;     BLEVEL LEAF_BLOCKS NUM_ROWS CLUSTERING_FACTOR---------- ----------- ---------- ----------------- 2 672 336500 1298Leaf  blocks  has  just  gone  up  by  just  1  but  it’s  enough  to  increase  the  BLEVEL  to  2  ...   The most comprehensive Oracle applications & technology content under one roof
  57. 57. 6.  BLEVEL  1  =>  BLEVEL  2    SQL>  select  *  from  major_tom  where  id  =  42;      Execution Plan-------------------------------------------------------------------------------------------| Id  | Operation                   | Name        | Rows  | Bytes | Cost (%CPU)| Time     |-------------------------------------------------------------------------------------------|   0 | SELECT STATEMENT            |             |     1 |    23 |     4   (0)| 00:00:01 ||   1 |  TABLE ACCESS BY INDEX ROWID| MAJOR_TOM   |     1 |    23 |     4   (0)| 00:00:01 ||*  2 |   INDEX RANGE SCAN          | MAJOR_TOM_I |     1 |       |     3   (0)| 00:00:01 |-------------------------------------------------------------------------------------------Statistics----------------------------------------------------------          1  recursive calls          0  db block gets          5  consistent gets          0  physical reads          0  redo size        531  bytes sent via SQL*Net to client        395  bytes received via SQL*Net from client          2  SQL*Net roundtrips to/from client          0  sorts (memory)          0  sorts (disk)          1  rows processedThe  cost  of  accessing  1  row  has  gone  up  by  2  as  the  BLEVEL  is  no  longer  ignored  by  the  CBO  ...     The most comprehensive Oracle applications & technology content under one roof
  58. 58. 6.  BLEVEL  1  =>  BLEVEL  2     SQL>  select  *  from  ziggy  z,  major_tom  m  where  m.id  =  z.id  and  z.code  in  (42,  4242);       68  rows  selected.       Execution Plan -------------------------------------------------------------------------------- | Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     | -------------------------------------------------------------------------------- |   0 | SELECT STATEMENT   |           |   200 |  9400 |  1485   (2)| 00:00:18 | |*  1 |  HASH JOIN         |           |   200 |  9400 |  1485   (2)| 00:00:18 | |*  2 |   TABLE ACCESS FULL| ZIGGY     |   200 |  4800 |  1105   (2)| 00:00:14 | |   3 |   TABLE ACCESS FULL| MAJOR_TOM |   336K|  7558K|   378   (1)| 00:00:05 | --------------------------------------------------------------------------------Nested  Loop  costs  (previously  1372)  have  gone  up  considerably  as  the  cost  has  gone  up  by  2  for  each  iteraFon  of  the  loop.    Hash  Join  and  FTS  now  selected  by  the  CBO  even  though  overall  size  of  index  is  similar.    Index  BLEVEL  can  potenFally  toggle  between  1  and  2  and  result  in  variable  performance  if  size  is  borderline  and  index  frequently  rebuilt  due  to  some  deleFons.   The most comprehensive Oracle applications & technology content under one roof
  59. 59. 7.  Why  Unique  Indexes  Are  Beyer  •  Since  Oracle8,  Non-­‐Unique  Indexes  Can  Police   Primary  and  Unique  Key  Constraints  •  Non-­‐Unique  Indexes  Necessary  For  Deferrable   and  NoValidate  Constraints  •  Non-­‐Unique  Indexes  are  not  automaFcally   dropped  when  constraint  is  dropped  or  disabled  •  However,  Unique  Indexes  are  not  outdated  and   are  generally  “beyer”  ...   The most comprehensive Oracle applications & technology content under one roof
  60. 60. 7.  Why  Unique  Indexes  Are  Beyer  SQL>  CREATE  TABLE  index_size_test  (id  NUMBER,  value  VARCHAR2(100)                        CONSTRAINT  index_size_test_pk_1  PRIMARY  KEY);    Table  created.    SQL>  INSERT  INTO  index_size_test  VALUES  (1,  DAVID  BOWIE);    1  row  created.    SQL>  COMMIT;    Commit  complete.    SQL>  SELECT  header_file,  header_block+1  FROM  dba_segments                        WHERE  segment_name  =  INDEX_SIZE_TEST_PK_1;    HEADER_FILE HEADER_BLOCK+1----------- -------------- 5 138370  SQL>  ALTER  SYSTEM  DUMP  DATAFILE  5  BLOCK  138370;    System  altered.   The most comprehensive Oracle applications & technology content under one roof
  61. 61. 7.  Why  Unique  Indexes  Are  Beyer  row#0[8016]  flag:  -­‐-­‐-­‐-­‐-­‐-­‐,  lock:  2,  len=20,  data:(6):    01  42  1c  7a  00  00  col  0;  len  11;  (11):    44  41  56  49  44  20  42  4f  57  49  45   SQL>  ALTER  TABLE  index_size_test  DROP  PRIMARY  KEY;     Table  altered.     SQL>  CREATE  INDEX  index_size_test_pk_2  ON  index_size_test(value);     Index  created.     SQL>  ALTER  TABLE  index_size_test  ADD  PRIMARY  KEY  (value);     Table  altered.  row#0[8015]  flag:  -­‐-­‐-­‐-­‐-­‐-­‐,  lock:  0,  len=21  col  0;  len  11;  (11):    44  41  56  49  44  20  42  4f  57  49  45  col  1;  len  6;  (6):    01  42  1c  7a  00  00   The most comprehensive Oracle applications & technology content under one roof
  62. 62. 7.  Why  Unique  Indexes  Are  Beyer  SQL>  CREATE  TABLE  test1  AS  SELECT  rownum  id  FROM  dual  CONNECT  BY  LEVEL  <=  1000000;  Table  created.    SQL>  CREATE  INDEX  non_unique_idx  ON  test1(id)  PCTFREE  0;  Index  created.    SQL>  CREATE  TABLE  test2  AS  SELECT  rownum  id  FROM  dual  CONNECT  BY  LEVEL  <=  1000000;  Table  created.    SQL>  CREATE  UNIQUE  INDEX  non_unique_idx  ON  test2(id)  PCTFREE  0;  Index  created.    SQL>  exec  dbms_stats.gather_index_stats(ownname=>BOWIE,  indname=>  NON_UNIQUE_IDX,  esFmate_percent=>  null);  PL/SQL  procedure  successfully  completed.    SQL>  exec  dbms_stats.gather_index_stats(ownname=>BOWIE,  indname=>UNIQUE_IDX,  esFmate_percent=>  null);  PL/SQL  procedure  successfully  completed.     The most comprehensive Oracle applications & technology content under one roof
  63. 63. 7.  Why  Unique  Indexes  Are  Beyer  SQL>  SELECT  index_name,  blevel,  leaf_blocks,  num_rows                        FROM  dba_indexes                        WHERE  index_name  IN  (NON_UNIQUE_IDX,  UNIQUE_IDX);    INDEX_NAME BLEVEL LEAF_BLOCKS NUM_ROWS-------------- ------ ----------- --------NON_UNIQUE_IDX 2 1999 1000000UNIQUE_IDX 2 1875 1000000 The  Non-­‐Unique  Index  has  used  an  extra  124  blocks  or   approximately  6.6%  more  blocks  than  the  Unique  Index     The most comprehensive Oracle applications & technology content under one roof
  64. 64. 7.  Why  Unique  Indexes  Are  Beyer  Unique  indexes  have  less  latching  and  CPU  related  overheads  ...  SQL>  CREATE  TABLE  ziggy  (id  NUMBER,  name  VARCHAR2(30));    Table  created.    SQL>  INSERT  into  ziggy  SELECT  rownum,  Bowie  FROM  dual  CONNECT  BY  level  <=1000;    1000  rows  created.    SQL>  COMMIT;    Commit  complete.    SQL>  ALTER  TABLE  ziggy  ADD  PRIMARY  KEY  (id);    Table  altered.    SQL>  exec  dbms_stats.gather_table_stats(ownname=>NULL,  tabname=>ZIGGY,  esFmate_percent=>  NULL,  method_opt=>  FOR  ALL  COLUMNS  SIZE  1);    PL/SQL  procedure  successfully  completed.   The most comprehensive Oracle applications & technology content under one roof
  65. 65. 7.  Why  Unique  Indexes  Are  Beyer  In  one  session,  run  the  following  a  couple  of  Fmes  to  ensure  no  recursive  SQL:  SQL>  SELECT  *  FROM  ziggy  WHERE  id  =  10;     ID NAME----- ----------------------- 10 BowieIn  other  session,  run  the  following  (where  SID  =  the  sid  of  the  other  session)  before  and  a‚er  an  execuFon  of  the  above  select  statement  in  the  other  session.  SQL>  SELECT  n.name,  s.value  FROM  v$sesstat  s,  v$statname  n                        WHERE  s.staFsFc#  =  n.staFsFc#  AND  s.sid  =  123  AND  n.name  like  consistent%;   The most comprehensive Oracle applications & technology content under one roof
  66. 66. 7.  Why  Unique  Indexes  Are  Beyer   NAME                                                                                                                                                            VALUE   -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐  -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   consistent  gets                                                                                                                              17703   consistent  gets  from  cache                                                                                    17703   consistent  gets  -­‐  examinaFon                                                                            10536   NAME                                                                                                                                                            VALUE   -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐  -­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐-­‐   consistent  gets                                                                                                                              17706   consistent  gets  from  cache                                                                                    17706   consistent  gets  -­‐  examinaFon                                                                            10539  Note  that  consistent  gets  increases  by  3,  consistent  gets  from  cache  increases  by  3,  consistent  gets  -­‐  examinaFon  increases  by  3  (1  for  the  index  root  block,  1  for  the  index  leaf  block  and  1  for  the  table  block).  That’s  a  total  of  3  CRs  and  3  latches  (as  all  CRs  are  the  cheaper  ‘examinaFons’  which  only  require  1  latch  each)   The most comprehensive Oracle applications & technology content under one roof
  67. 67. 7.  Why  Unique  Indexes  Are  Beyer  Now  the  same  test  but  this  Fme  with  a  non-­‐unique  index  ...  SQL>  ALTER  TABLE  ziggy  DROP  PRIMARY  KEY;    Table  altered.    SQL>  ALTER  TABLE  ziggy  ADD  PRIMARY  KEY  (id)  USING  INDEX      2    (CREATE  INDEX  ziggy_id_i  ON  ziggy(id));    Table  altered.    SQL>  exec  dbms_stats.gather_table_stats(ownname=>NULL,  tabname=>ZIGGY,  esFmate_percent=>  NULL,  method_opt=>  FOR  ALL  COLUMNS  SIZE  1);    PL/SQL  procedure  successfully  completed.   The most comprehensive Oracle applications & technology content under one roof

×