Oracle NZ - Francisco Munoz Alvarez

28. July 2010

Come and ask Tom in NZ!

Filed under: News, Others — admin @ 08:57

nzoug_otn_days

27. July 2010

Next stop: Insync’10 , NZOUG OTN Days and Sangam’10

Filed under: News, Questions — admin @ 05:44

I received some emails recently asking were will be my next presentations, and to make it public here we go:

  • Insync’10, Melbourne August 16 – Topic: Tips and Best Practices for DBAs @ 9:55AM to 10:40 AM more info at  http://www.insync-conference.com.au/
  • NZOUG OTN Days, August 18 in Auckland and August 20 in Wellington – Topic How to Improve your Oracle Career more info at http://www.nzoug.org
  • Sangam’10,  Hyderabad September 3-4 – Topics: Making magic with Oracle & Tips and Best Practices for DBAs more info at http://www.aioug.org/sangam10.php

Kind Regards,

Francisco Munoz Alvarez

Speaker_large  SANGAM10-web NZOUGLogo

26. July 2010

NZOUG and LAOUC June and July Webinars (Recording)

Filed under: 11gR2, DBA Career Tips, Tutorials, Questions, General — admin @ 02:15

Hi All,

NZOUG (New Zealand Oracle Users Group) and LAOUC (Latin American Oracle Users Communty) is organizing a serie of webinars to Oracle Community (over 42 Webinars) with the participation of several Oracle Celebrities, and is my desire to share the first 8 webinars recorded with all Oracle Users around the world!

Please find bellow all the webinars recorded in the past 2 months for LAOUC and NZOUG, I want to express a special thank you to: Arup Nanda, Daniel Morgan, Debra Lilley, Alex Gorbachev and Ben Prusinski for their invaluable participation (Alex Webinar recording is coming soon) and  for the incredible desire to share their knowledge with the community!

Arup Nanda Presenting
Under the Hoods of Cache Fusion, GES, GCS and GRD

Daniel Morgan Presenting
11gR2 Edition Based Redefinition

Ben Prusinski Presenting 
Tip & Tricks Patching EBS R12

Arup Nanda Presenting 
RAC Performance Tuning

Daniel Morgan Presenting
How to Read and Interpret an Explain Plan

Arup Nanda Presenting
How to Secure Your DB in one Day

Debra Lilley Presenting
Fusion Applications, What’s behind it!

 

1. June 2010

Fun and Networking in Sweden and Estonia

Filed under: Questions — admin @ 00:55

May was a fantastic month for networking and fun in Europe! Orcan Spring Conference and EMEA Harmony were two great conferences and my sincere congratulations to all the people involved to the success of both events. In these events I had the opportunity to see again some great friends like Joze Senegacnik, Daniel Morgan, Heli Helskyaho and Tom Kyte and also gave me the opportunity to make some new ones like: Piet de Visser, Debra Lilley, Chris J. Date,  Dimitri Gielis,  Mogens Norgaard, Tanel Poder,Tiina Lehtovaara, Patrik Norlander, Jesper Karlsson, Andrejs Vorobjovs, Hüsnü Şensoy, Luca Canali, Stanley and a lot more of great and fantastic people!

Bellow you can see some photos of the trip (more are available in my facebook), you can see some good friends and  moments, also Debra cooking Stanley and later in the day shooting the poor Stanley, he inclusive end the trip looking for some kind of protection against Debra as you can see bellow;)

I really loved these events and hope to be invite again next year! Soon will post my presentations here.

fco_piet 01_tallin IMG_8936

stanley_me IMG_8876IMG_8863IMG_9240

   IMG_9037IMG_9343Orcan%20Hasseludden%202010%20041Orcan%20Hasseludden%202010%20010

IMG_8970 IMG_8977 IMG_8979

IMG_8978 IMG_8992 IMG_9018 

IMG_9044  IMG_9087 IMG_9305

IMG_9315  Orcan%20Hasseludden%202010%20064 Orcan%20Hasseludden%202010%20046 

Orcan%20Hasseludden%202010%20011  

Hope to see everyone soon!

Francisco Munoz Alvarez

29. April 2010

Tip of the Month: How to have super powers using Data Pump!

Filed under: Backup & Recovery, DBA Career Tips, Tutorials, General — admin @ 02:49

A lot of people don’t know several powerful functionalities that we have available when using Data Pump (expdp/impdp), most of the people only use these tools to export and import data (in other words, only to move data), and never notice that it can be used for example to help us to do:

  • Data Masking
  • Build a Metadata Repository
  • Create a version control
  • Clone Users (Create a new user using and existent user as a template)
  • Create smaller copies of production
  • Create your database in a different file structure
  • Move all objects from one tablespace to another
  • Move a object to a different schema (A simple example, change a table owner)

Now let’s see how each functionality I mentioned above can be used at real life.

1) Data Masking

In many organizations (I hope so) the DBA’s had the obligation for a security and compliance purpose to mask all sensible information that leaves the production environment to as an example to refresh or create a QA/Test or Dev environment. To help us to address this kind of requirements we could easily use the Enterprise Manager Data Masking Pack (remember it is an extra pack, and consequently you need to pay extra to use it), or as a different option, use the “remap_data” parameter available in Data Pump to help you with this requirement(**this is a new functionality at 11g)!

Let’s use the classic SSN (Social Security Number) example to illustrate how it works:

a) First let’s create the table for the test and load some data on it.



SQL> CREATE TABLE HR.EMPLOYEE
  2  ( EMP_ID   NUMBER(10) NOT NULL,
  3    EMP_NAME VARCHAR2(30),
  4    EMP_SSN  VARCHAR2(9),
  5    EMP_DOB  DATE
  6* )
SQL> /


insert into hr.employee values (101,‘Francisco Munoz’,123456789,’30-DEC-73′);
insert into hr.employee values (102,‘Horacio Miranda’,234567890,’17-JUL-76′);
insert into hr.employee values (103,‘Evelyn Aghemio’,659812831,’02-OCT-79′);

b) The second step will be to create the remap function:


SQL> create or replace package pkg_masking
   2 as
   3 function mask_ssn (p_in varchar2) return varchar2;
   4 end;
   5 /

SQL> create or replace package body pkg_masking
   2 as
   3 function mask_ssn (p_in varchar2)
   4 return varchar2
   5 is
   6 begin
   7 return lpad (
   8 round(dbms_random.value (001000000,999999999)),9,0);
   9 end;
  10 end;
  11 /

This function will take a varchar argument and returns a 9 char. We will use this function to mask all SSN information inside our employee table.


SQL> desc employee

Name                                      Null?    Type
----------------------------------------- -------- ----------------------------
EMP_ID                                    NOT NULL NUMBER(10)
EMP_NAME                                           VARCHAR2(30)
EMP_SSN                                            VARCHAR2(9)
EMP_DOB                                            DATE

SQL> select * from employee;

EMP_ID     EMP_NAME                       EMP_SSN   EMP_DOB
---------- ------------------------------ --------- ---------
101        Francisco Munoz                123456789 30-DEC-73
102        Horacio Miranda                234567890 17-JUL-76
103        Evelyn Aghemio                 345678901 02-OCT-79

For this example, all you want to mask is the column EMP_SSN, which contains the SSN of each employee.

b) Now we are going to export the table employees using the expdp tool, and while exporting, we will use the parameter “remap_data” to mask the data for us in the dump file using the function we previously created.


$ expdp hr/hr tables=hr.employee dumpfile=mask_ssn.dmp directory=datapump remap_data=hr.employee.emp_ssn:pkg_masking.mask_ssn

Note: By defect the “remap_data” parameter will use the user doing the export as the owner of the remap function, if the schema owner of the function is different you will need to use the following commad:


$ expdp hr/hr tables=hr.employee dumpfile=mask_ssn.dmp directory=datapump remap_data=hr.employee.emp_ssn:owner.pkg_masking.mask_ssn

c) Now all we need to do is to import the mask_ssn.dmp in our QA/Test or Dev Database and it will magically have the new values there.


SQL> select * from employee;
EMP_ID     EMP_NAME                       EMP_SSN   EMP_DOB
---------- ------------------------------ --------- ---------
101        Francisco Munoz                108035616 30-DEC-73
102        Horacio Miranda                324184688 17-JUL-76
103        Evelyn Aghemio                 638127075 02-OCT-79

Note: you can use the “remap_data” option in the impdp tool if you have a normal export done before ;) , also remember that you can use it to mask almost everything, but please take in consideration your application requirements and data integrity requirements when using it!

For more information regarding this option and to see another examples, please refer to this paper: http://www.oracle.com/technology/products/database/utilities/pdf/datapump11g2009_transform.pdf

2) Metadata Repository and Version Control

As a DBA, I’m always looking for proactive ways to allow me to be prepared in case of a disaster strike or if an emergency release rollback is required (I love to use always the “What if” methodology), and due to these reasons, have a metadata repository and version control of it is always useful .

But how can I easily create it? Easy, first do a full backup of your database using Datapump.


$ expdp user/password content=metadata_only full=y directory=datapump dumpfile=metadata_24112010.dmp

Note: If you want to create a repository only for objects like procedures, packages, triggers, … , all you need to do is add the parameter “include=<procedures,packages,triggers,…> to your expdp command, I usually include in the dump file name the date of the dump for reference purpose and best practice.

Then use the impdp tool to create the SQL file that will allow you to create all objects in your Database. It will be something like this:


$ impdp user/password directory=datapump dumpfile= metadata_24112010.dmp sqlfile=metadata_24112010.sql

This simple technique will allow you to create your metadata repository easily and also keep a versioning of your database objects as an extra, also if you create your repository (DB) and you want to refresh an object definition (as example let use the table emp from schema “scott”), all you will need to do is an export of the new table definition from your source database and then import it on your target database (your repository) as show bellow:


$ expdp user/password content=metadata_only tables=scott.emp directory=datapump dumpfile= refresh_of_table_emp_24112010.dmp

$ impdp user/password table_exists_action=replace directory=datapump dumpfile= refresh_of_table_name_24112010.dmp


3) Clone a User

In the past when a DBA had the need to create a new user with the same structure (All objects, tablespaces quota, synonyms, grants, system privileges, etc) was a very painful experience, now all can be done very easily using Data Pump, let use as an example that you want to create the user ”Z” exactly like the user “A”, to achieve this goal all you will need to do is first export the schema “A” definition and then import it again saying to the Data Pump to change the schema “A” for the new schema named “Z” using the “remap_schema” parameter available with impdp.


$ expdp user/password schemas=A content=metadata_only directory=datapump dumpfile= A_24112010.dmp

$ impdp user/password remap_schema=A:Z directory=datapump dumpfile= A_24112010.dmp

And your new user Z is now created like your existing user A , that easy!

4) Create smaller copies of production

That is a very common task for a DBA, you are always having a task to create a copy of your Database (for development or test purpose) but your destination server don’t have enough space to create a full copy of it! This can be easily solved with Data Pump, for this example, let say that you only have space for 70% of your production database, now to know how to proceed, we need to decide if the copy will contain metadata only (no data/rows) or if it will include the data also. Let’s see how to do each way:

a) Metadata Only

First do a full export of your source database.


$ expdp user/password content=metadata_only full=y directory=datapump dumpfile=metadata_24112010.dmp

Then, let’s import the metadata and tell the Data Pump to reduce the size of extents to 70%, you can do it using the parameter “transform” available with “impdp”, it represent the percentage multiplier that will be used to alter extent allocations and datafiles size.


$ impdp user/password transform=pctspace:70 directory=datapump dumpfile=metadata_24112010.dmp

Let’s do a test and see if this is really true, first let export any table of my test database (metadata only) and generate the “sql” script to see the normal size of it.


$expdp user/password content=metadata_only tables=user.x_integration_log_det directory=datapump dumpfile=example_24112010.dmp

$impdp user/password content=metadata_only directory=datapump dumpfile=example_24112010.dmp sqlfile=x_24112010.sql

CREATE TABLE "USER“.”X_INTEGRATION_LOG_DET
      ( "BATCH_NO” NUMBER(9,0),
        "SEQUENCE#” NUMBER(9,0),
        "FILENAME” VARCHAR2(200 BYTE),
        "ERROR_MESSAGE” VARCHAR2(2000 BYTE),
        "NO_OF_RECORDS” NUMBER,
        "STATUS” VARCHAR2(2000 BYTE)
      ) PCTFREE 10 PCTUSED 0 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "CUSTSERV_LOG_DET_DATA” ;

Above is the SQL code generated by Data Pump, you can see that the table is going to be created using 65536 for the initial extent and 1048576 for the next extent, now let’s generate it again but using the transform parameter to reduce the size of it to 70% of original size.


$impdp user/password transform=pctspace:70 content=metadata_only directory=datapump dumpfile=example_24112010.dmp sqlfile=x_24112010.sql

CREATE TABLE "USER“.”X_INTEGRATION_LOG_DET
    ( "BATCH_NO” NUMBER(9,0),
      "SEQUENCE#” NUMBER(9,0),
      "FILENAME” VARCHAR2(200 BYTE),
      "ERROR_MESSAGE” VARCHAR2(2000 BYTE),
      "NO_OF_RECORDS” NUMBER,
      "STATUS” VARCHAR2(2000 BYTE)
    ) PCTFREE 10 PCTUSED 0 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 45875 NEXT 734003 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "CUSTSERV_LOG_DET_DATA” ;

Above is the SQL code generated by Data Pump, and you can see that the table is now going to be created using 45875 for the initial extent and 734003 for the next extent, clearly reduced 30% of the original size, in other words, it works.

Please refer to Oracle documentation for more ways to use the transform parameter, you will not regret ;)

b) Metadata and data

First does a full export of your source database using the export parameter “sample”, this parameter specify a percentage of the data rows to be sampled and unload from your source database, in this case let’s use 70%.


$ expdp user/password sample=70 full=y directory=datapump dumpfile=expdp_70_24112010.dmp

Then, all you need to do as the example before is to import it telling the Data Pump to reduce the size of extents to 70%, and that’s it!


$ impdp user/password transform=pctspace:70 directory=datapump dumpfile=expdp_70_24112010.dmp

5) Create your database in a different file structure

This is very easy to archive, all you need to do is use the parameter “remap_datafile” on your import command as the example bellow:


$ impdp user/password directory=datapump dumpfile=example_24112010.dmp remap_datafile=’/u01/app/oracle/oradata/datafile_01.dbf’:’/u01/datafile_01.dbf’

6) Move all objects from one tablespace to another

This is very easy to do it, as the previous example, all you will need to do is use the parameter “remap_tablespace” on your import command as the example bellow:


$ impdp user/password directory=datapump dumpfile=example_24112010.dmp remap_tablespace=OLD_TBS:NEW_TBS

7) Move a object to a different schema

All you will need to do is use the parameter remap_schema as the example bellow when importing it.


$ expdp user/password tables=user.table_name directory=datapump dumpfile=table_name_24112010.dmp

$ impdp user/password directory=datapump dumpfile=table_name_24112010.dmp remap_schema=old_schema:new_schema

Always remember, Data Pump is your good friend, but RMAN still your best friend ;). You can easily guess my next month topic will be…  :p

28. April 2010

OracleNZ, 2 years and 294,679 Unique Visitors Later

Filed under: News — admin @ 11:32

This week was my blog 2nd anniversary, it’s incredible how the time fly, after two years and 294,679 unique visitors, looks like was yesterday when I started this blog. Thank you for follow me and read my posts, you are the real reason that keep me working on this blog  :)

 image  image   image

6. April 2010

Discovering the New Zealand Oracle Market

Filed under: News, Others, General — admin @ 03:50

The New Zealand conference this year was a great event, with a little over 150 participants and with a fantastic group of speakers and topics (For more information please refer to http://www,nzoug.org ).

DSC_3493

From Left to Right: Guy Harrison, Chris Muir, Tim Hall, Robert Freeman, Daniel Morgan, and Francisco Munoz Alvarez.

During the event, my company  (Database Integrated Solutions http://www.dbisonline.com) was doing a pool to see the reality of the New Zealand market, 87 delegates from 31 different companies answered our questionary, and here are the results:

image image

image image

image image

Thanks’ to all NZOUG participants and hope to see everyone again next year!

Cheers,

Francisco Munoz Alvarez

24. March 2010

Tip of the month – Magic for DBAs

Filed under: Oracle FAQ, Tutorials, Tuning, General — admin @ 06:30

Who never had a problem with a SQL that is killing your Database Performance and you can’t fix it because it’s running from an external closed application that you or your developers can’t touch?

Since Oracle version 10 this is a problem of the past, now you can easy solve this kind of problem using the DBMS_ADVANCED_REWRITE package, which allow you to transform/customize queries on the fly, changing for example one query with bad explain plan for another one with a good explain plan.

Before you become too excited, please remember the following restrictions: 

  • It does not work with bind variables.(Alternative solution at Metalink Doc ID. 392214.1)
  • Only works for the SELECT statement.
  • Does not work when the base table is modified through DML.

To see how it works, first we will need to grant execute privileges on the package to our user called test and allow it to create materialized views.


CONN sys/password AS SYSDBA
GRANT EXECUTE ON DBMS_ADVANCED_REWRITE TO test;
GRANT CREATE MATERIALIZED VIEW TO test;

Now let’s create and populate our objects for test purpose:


CONN test/test

CREATE TABLE students (
  student_id               NUMBER(10),
  student_name             VARCHAR2(45),
  student_status           VARCHAR2(1),
  student_year             number(2),
  student_address          varchar2(45),
  student_city             varchar2(16),
  student_zip              number(6),
  student_social_security  number(10))
/

ALTER TABLE students
ADD CONSTRAINT pk_student PRIMARY KEY (student_id)
USING INDEX
PCTFREE 0;

BEGIN
  INSERT INTO STUDENTS VALUES (1,'PAUL COOK','Y',9,'5 Main Road','Auckland',2031,100101000);
  INSERT INTO STUDENTS VALUES (2,'HORACIO MIRANDA','Y',8,'15 Main Road','Auckland',2031,100101001);
  INSERT INTO STUDENTS VALUES (3,'SCOTT PEDERSEN','Y',7,'13 Main Road','Auckland',2031,100101002);
  INSERT INTO STUDENTS VALUES (5,'SETH PICKERING','Y',9,'12 Main Road','Auckland',2031,100101003);
  INSERT INTO STUDENTS VALUES (6,'FRANCISCO ALVAREZ','Y',11,'11 Main Road','Auckland',2031,100101004);
  INSERT INTO STUDENTS VALUES (7,'ALTMAAR VISSER','Y',9,'16 Main Road','Auckland',2031,100101005);
  INSERT INTO STUDENTS VALUES (9,'REYNALDO OCFEMIA','Y',6,'25 Main Road','Auckland',2031,100101006);
  INSERT INTO STUDENTS VALUES (15,'CAMERON PITCHES','Y',12,'31 Main Road','Auckland',2031,100101007);
  INSERT INTO STUDENTS VALUES (18,'MONIQUE GENNIP','Y',8,'71 Main Road','Auckland',2031,100101008);
  INSERT INTO STUDENTS VALUES (99,'TERRENCE LO','Y',6,'17 Main Road','Auckland',2031,100101009);
  INSERT INTO STUDENTS VALUES (100,'KIM FONG','Y',11,'16 Main Road','Auckland',2031,100101010);
  INSERT INTO STUDENTS VALUES (103,'CHRIS OPPERMAN','Y',12,'7 Main Road','Auckland',2031,100101011);
  INSERT INTO STUDENTS VALUES (104,'SCOTT TIGER','Y',6,'62 Main Road','Auckland',2031,100101012);
  INSERT INTO STUDENTS VALUES (105,'EVELYN AGHEMIO','Y',11,'32 Main Road','Auckland',2031,100101013);
  INSERT INTO STUDENTS VALUES (106,'TOMAS MUNOZ','Y',11,'18 Main Road','Auckland',2031,100101014);
  INSERT INTO STUDENTS VALUES (107,'GONZALO TORRES','Y',10,'14 Principal Road','Auckland',2031,100101015);
  INSERT INTO STUDENTS VALUES (108,'JOHN KEY','Y',10,'12 Principal Road','Auckland',2031,100101016);
  INSERT INTO STUDENTS VALUES (109,'JOHN A','Y',7,'21 Principal Road','Auckland',2031,100101017);
  INSERT INTO STUDENTS VALUES (111,'JOHN B','Y',9,'121 Principal Road','Auckland',2031,100101018);
  INSERT INTO STUDENTS VALUES (112,'JOHN C','Y',8,'321 Principal Road','Auckland',2031,100101019);
  INSERT INTO STUDENTS VALUES (113,'JOHN D','Y',6,'35 Principal Road','Auckland',2031,100101020);
  INSERT INTO STUDENTS VALUES (114,'JOHN E','Y',12,'41 Principal Road','Auckland',2031,100101021);
  INSERT INTO STUDENTS VALUES (116,'JOHN F','Y',8,'161 Principal Road','Auckland',2031,100101022);
  INSERT INTO STUDENTS VALUES (10,'JOHN G','Y',7,'171 Principal Road','Auckland',2031,100101023);
  INSERT INTO STUDENTS VALUES (311,'JOHN H','Y',11,'353 Principal Road','Auckland',2031,100101024);
  INSERT INTO STUDENTS VALUES (312,'JOHN I','Y',7,'351 Principal Road','Auckland',2031,100101025);
  INSERT INTO STUDENTS VALUES (319,'JOHN K','Y',9,'352 Principal Road','Auckland',2031,100101026);
  INSERT INTO STUDENTS VALUES (322,'JOHN L','Y',6,'353 Principal Road','Auckland',2031,100101027);
  INSERT INTO STUDENTS VALUES (333,'JOHN M','Y',11,'354 Principal Road','Auckland',2031,100101028);
  INSERT INTO STUDENTS VALUES (343,'JOHN N','Y',6,'355 Principal Road','Auckland',2031,100101029);
  INSERT INTO STUDENTS VALUES (344,'JOHN O','Y',7,'356 Principal Road','Auckland',2031,100101030);
  INSERT INTO STUDENTS VALUES (345,'JOHN P','Y',8,'357 Principal Road','Auckland',2031,100101031);
  INSERT INTO STUDENTS VALUES (346,'JOHN Q','Y',9,'358 Principal Road','Auckland',2031,100101032);
  INSERT INTO STUDENTS VALUES (347,'JOHN R','Y',10,'359 Principal Road','Auckland',2031,100101033);
  INSERT INTO STUDENTS VALUES (350,'JOHN S','Y',11,'360 Principal Road','Auckland',2031,100101034);
  INSERT INTO STUDENTS VALUES (530,'JOHN T','Y',12,'361 Principal Road','Auckland',2031,100101035);
  INSERT INTO STUDENTS VALUES (531,'JOHN U','Y',13,'362 Principal Road','Auckland',2031,100101036);
  INSERT INTO STUDENTS VALUES (533,'JOHN V','N',6,'35 Principal Road','Auckland',2031,100101037);
  INSERT INTO STUDENTS VALUES (534,'JOHN X','N',8,'13 Principal Road','Auckland',2031,100101038);
  INSERT INTO STUDENTS VALUES (535,'JOHN Z','N',7,'135 Principal Road','Auckland',2031,100101039);
  INSERT INTO STUDENTS VALUES (536,'JOHN Y','N',11,'435 Principal Road','Auckland',2031,100101040);
  INSERT INTO STUDENTS VALUES (537,'JOHN W','Y',8,'635 Principal Road','Auckland',2031,100101041);
  INSERT INTO STUDENTS VALUES (539,'ARTUR JOHNES','Y',6,'22 Secondary Road','Auckland',2031,100101042);
  INSERT INTO STUDENTS VALUES (540,'KING PANTHER','Y',7,'22 Secondary Road','Auckland',2031,100101043);
  INSERT INTO STUDENTS VALUES (541,'PINK PANTHER','Y',8,'22 Secondary Road','Auckland',2031,100101044);
  INSERT INTO STUDENTS VALUES (542,'HAROLD ROBINS','Y',9,'221 Secondary Road','Auckland',2031,100101045);
  INSERT INTO STUDENTS VALUES (543,'CHRIS BONES','Y',8,'222 Secondary Road','Auckland',2031,100101046);
  INSERT INTO STUDENTS VALUES (545,'TIM TOM','Y',9,'223 Secondary Road','Auckland',2031,100101047);
  INSERT INTO STUDENTS VALUES (546,'TIM JONES','Y',10,'223 Secondary Road','Auckland',2031,100101048);
  INSERT INTO STUDENTS VALUES (547,'MICHAEL JONES','Y',11,'224 Secondary Road','Auckland',2031,100101049);
  INSERT INTO STUDENTS VALUES (548,'ANN SMITH','Y',12,'225 Secondary Road','Auckland',2031,100101050);
  INSERT INTO STUDENTS VALUES (549,'JOHN SMITH','Y',13,'226 Secondary Road','Auckland',2031,100101051);
  INSERT INTO STUDENTS VALUES (551,'PAUL STONE','Y',6,'227 Secondary Road','Auckland',2031,100101052);
  INSERT INTO STUDENTS VALUES (552,'CARL SMITH','Y',7,'228 Secondary Road','Auckland',2031,100101053);
  INSERT INTO STUDENTS VALUES (553,'TEST','Y',8,'229 Secondary Road','Auckland',2031,100101054);
  COMMIT;
END;
/

CREATE TABLE grades (
  student_id       NUMBER(10),
  grade   NUMBER(6,2),
  grade_subject    VARCHAR2(4),
  grade_date       DATE,
  grade_note      VARCHAR2(60))
/

ALTER TABLE grades
ADD CONSTRAINT pk_GRADES PRIMARY KEY (student_id, grade, grade_subject,grade_date)
USING INDEX
PCTFREE 0;

ALTER TABLE grades
ADD CONSTRAINT fk_students
FOREIGN KEY (student_id)
REFERENCES students(student_id);

BEGIN
  INSERT INTO GRADES VALUES (553,100.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (552,95.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (551,87.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (549,87.5,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (548,90.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (547,64.7,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (546,85.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (545,88.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (543,98.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (542,95.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (541,94.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (540,94.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (539,95.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (1,88.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (2,98.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (3,98.7,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (5,96.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (6,97.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (7,90.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (9,91.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (15,92.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (18,93.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (99,94.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (100,95.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (533,98.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (534,100.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (535,100.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (536,99.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (537,88.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (530,88.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (531,88.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (103,67.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (104,56.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (105,93.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (106,88.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (107,72.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (108,71.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (109,68.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (111,77.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (112,87.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (113,65.5,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (114,34.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (116,91.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (10,98.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (311,78.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (312,88.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (319,67.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (322,89.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (333,95.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (343,91.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (344,98.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (345,87.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (346,93.0,'ENGL',sysdate,null);
  INSERT INTO GRADES VALUES (347,99.0,'ENGL',sysdate,null);
  COMMIT;
  INSERT INTO GRADES VALUES (553,100.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (552,95.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (551,87.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (549,87.5,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (548,90.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (547,64.7,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (546,85.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (545,88.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (543,98.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (542,95.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (541,94.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (540,94.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (539,95.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (1,88.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (2,98.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (3,98.7,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (5,96.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (6,97.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (7,90.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (9,91.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (15,92.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (18,93.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (99,94.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (100,95.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (533,98.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (534,100.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (535,100.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (536,99.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (537,88.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (530,88.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (531,88.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (103,67.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (104,56.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (105,93.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (106,88.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (107,72.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (108,71.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (109,68.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (111,77.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (112,87.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (113,65.5,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (114,34.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (116,91.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (10,98.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (311,78.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (312,88.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (319,67.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (322,89.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (333,95.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (343,91.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (344,98.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (345,87.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (346,93.0,'MATH',sysdate-7,null);
  INSERT INTO GRADES VALUES (347,99.0,'MATH',sysdate-7,null);
  COMMIT;
  INSERT INTO GRADES VALUES (553,100.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (552,95.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (551,87.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (549,87.5,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (548,90.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (547,64.7,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (546,85.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (545,88.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (543,98.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (542,95.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (541,94.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (540,94.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (539,95.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (1,88.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (2,98.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (3,98.7,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (5,96.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (6,97.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (7,90.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (9,91.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (15,92.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (18,93.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (99,94.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (100,95.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (533,98.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (534,100.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (535,100.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (536,99.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (537,88.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (530,88.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (531,88.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (103,67.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (104,56.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (105,93.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (106,88.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (107,72.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (108,71.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (109,68.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (111,77.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (112,87.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (113,65.5,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (114,34.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (116,91.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (10,98.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (311,78.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (312,88.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (319,67.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (322,89.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (333,95.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (343,91.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (344,98.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (345,87.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (346,93.0,'BIOL',sysdate,null);
  INSERT INTO GRADES VALUES (347,99.0,'BIOL',sysdate,null);
  COMMIT;
  INSERT INTO GRADES VALUES (553,100.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (552,95.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (551,87.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (549,87.5,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (548,90.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (547,64.7,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (546,85.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (545,88.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (543,98.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (542,95.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (541,94.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (540,94.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (539,95.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (1,88.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (2,98.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (3,98.7,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (5,96.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (6,97.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (7,90.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (9,91.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (15,92.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (18,93.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (99,94.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (100,95.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (533,98.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (534,100.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (535,100.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (536,99.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (537,88.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (530,88.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (531,88.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (103,67.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (104,56.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (105,93.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (106,88.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (107,72.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (108,71.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (109,68.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (111,77.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (112,87.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (113,65.5,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (114,34.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (116,91.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (10,98.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (311,78.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (312,88.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (319,67.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (322,89.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (333,95.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (343,91.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (344,98.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (345,87.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (346,93.0,'ARTS',sysdate,null);
  INSERT INTO GRADES VALUES (347,99.0,'ARTS',sysdate,null);
  COMMIT;
END;
/

Now let simulate that you found the SQL bellow running in your Database:


SQL> Explain plan for
select student_name,avg(a.grade) from grades a, students b
where b.student_social_security = 100101016
and   b.student_id = a.student_id
group by student_name
/

STUDENT_NAME                                  AVG(A.GRADE)
--------------------------------------------- ------------
JOHN KEY                                                71

SQL> SELECT * FROM TABLE(dbms_xplan.display);

Plan hash value: 3187331965

---------------------------------------------------------------------------------
| Id  | Operation           | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |           |     4 |   304 |     5  (20)| 00:00:01 |
|   1 |  HASH GROUP BY      |           |     4 |   304 |     5  (20)| 00:00:01 |
|   2 |   NESTED LOOPS      |           |     4 |   304 |     4   (0)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL| STUDENTS  |     1 |    50 |     3   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN | PK_GRADES |     4 |   104 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------
   3 - filter("B“.”STUDENT_SOCIAL_SECURITY“=100101016)
   4 - access("B“.”STUDENT_ID“=”A“.”STUDENT_ID“)

Note
-----
   - dynamic sampling used for this statement

You can see that the SQL above is doing a full scan to the students table, after a few modifications we have another SQL, a little more efficient, and it will be:



SQL> Explain plan for
select student_name,avg(a.grade) from grades a, students b
where b.student_id = 108
and   b.student_id = a.student_id
group by student_name
/

STUDENT_NAME                                  AVG(A.GRADE)
--------------------------------------------- ------------
JOHN KEY                                                71

Execution Plan
----------------------------------------------------------

Plan hash value: 3300694555

--------------------------------------------------------------------------------------------
| Id  | Operation                     | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |            |     4 |   252 |     2   (0)| 00:00:01 |
|   1 |  HASH GROUP BY                |            |     4 |   252 |     2   (0)| 00:00:01 |
|   2 |   NESTED LOOPS                |            |     4 |   252 |     2   (0)| 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID| STUDENTS   |     1 |    37 |     1   (0)| 00:00:01 |
|*  4 |     INDEX UNIQUE SCAN         | PK_STUDENT |     1 |       |     1   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN           | PK_GRADES  |     4 |   104 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------
   4 - access("B“.”STUDENT_ID“=108)
   5 - access("A“.”STUDENT_ID“=108)

Note
-----
   - dynamic sampling used for this statement

You can see that the second SQL is more efficient that the first one, and for that reason we will order Oracle to replace the bad SQL for the good one every time the bad SQL is executed, how we can do it? Easily, the magic will be:



SQL> ALTER SESSION SET QUERY_REWRITE_INTEGRITY = TRUSTED;

SQL> BEGIN
       sys.dbms_advanced_rewrite.declare_rewrite_equivalence (
       name              => 'test_rw1',
       source_stmt =>
       'select student_name,avg(a.grade)
       from grades a, students b
       where b.student_social_security = 100101016
       and b.student_id = a.student_id
       group by student_name',
       destination_stmt =>
       'select student_name,avg(a.grade)
       from grades a, students b
       where b.student_id = 108
       and   b.student_id = a.student_id
       group by student_name',
       validate  => false,
       rewrite_mode      => 'text_match');
     END;
     /

Let’s now see if the magic really works:


SQL> Explain plan for
select student_name,avg(a.grade) from grades a, students b
where b.student_social_security = 100101016
and   b.student_id = a.student_id
group by student_name
/

STUDENT_NAME                                  AVG(A.GRADE)
--------------------------------------------- ------------
JOHN KEY                                                71

SQL> SELECT * FROM TABLE(dbms_xplan.display);

Execution Plan
----------------------------------------------------------

Plan hash value: 3300694555

--------------------------------------------------------------------------------------------
| Id  | Operation                     | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |            |     4 |   252 |     2   (0)| 00:00:01 |
|   1 |  HASH GROUP BY                |            |     4 |   252 |     2   (0)| 00:00:01 |
|   2 |   NESTED LOOPS                |            |     4 |   252 |     2   (0)| 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID| STUDENTS   |     1 |    37 |     1   (0)| 00:00:01 |
|*  4 |     INDEX UNIQUE SCAN         | PK_STUDENT |     1 |       |     1   (0)| 00:00:01 |
|*  5 |    INDEX RANGE SCAN           | PK_GRADES  |     4 |   104 |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------
   4 - access("B“.”STUDENT_ID“=108)
   5 - access("A“.”STUDENT_ID“=108)

Note
-----
   - dynamic sampling used for this statement

The magic is done, now every time the source_stmt is execute it will be replaced by the destination_stmt with a better execution plan :)

Enjoy this trick!

Kind Regards,

Francisco Munoz Alvarez

19. January 2010

DBA Tip of the Month: Jan/2010

Filed under: Backup & Recovery, DBA Career Tips, General — admin @ 07:44

I want to start this New Year creating a new session on my blog called “DBA Tip of the month” where I will try to post every month an important tip to help all fellows DBAs to improve their careers.

The first topic of this session will be:
 

Being Proactive with Backup & Recovery”

Always when I arrive on a new client I ask the DBA on charge the following questions:

  • Do you have your recovery strategy documented step by step?
  • Are you 100% sure that your tape backups are usable?
  • Do you know exactly how long a recovery on your production environment will take if necessary?

And almost 90% of the time the answers will be:

  • No!
  • I not sure, but I think so!
  • No idea, probably…!

You will be on shock to know how many times I’m call to support a DBA to try to recover a Database because the most current tape backup is unusable!

Backup & Recovery are a very important (crucial) part of a DBA role, as a DBA I’ll never be stressed enough to repeat over and over what in my opinion is the most important rule for a DBA:

“The most important rule with respect to data is to never put yourself into an unrecoverable situation.”

You know, because bad stuff happen….
Bad 1Bad 2Bad 3
…When you less expect, and due to this, I’ll always recommend a DBA to perform a proactive approach to his/her Database Backup and Recovery strategy.

The main idea is:

  1. Randomly choose a backup tape and recovery it on a test machine (It can be a virtual one).
  2. Take this opportunity to document all the recover process.
  3. Review the entire process ant try to improve it!
  4. Repeat this exercise every month and try to involve other DBAs in the process!

This easy process will allow you to:

  1. Test your Tape backups and see if they are being backup correctly.
  2. Check and improve your recovery knowledge and strategy.
  3. Document all your recovery process that could be used for any other DBA in the company in case you are not available in the recovery situation.
  4. Detect any error on your backup & recovery strategy.
  5. Know your recovery time. Next time your manager asks you” Do you know how long a recovery will take? You will know the exact answer.
  6. Have an opportunity to review your process and try to make it more efficient.

Like you can see, this is an easy proactive exercise that will allow you and your company to be prepared in case of a disaster and recovery situations occurs, and you know when this always happens….
 Sleep

Cheers,

Francisco Munoz Alvarez

16. December 2009

DB_ULTRA_SAFE a new GEM for High Availability

Filed under: Oracle FAQ, 11gR2, DBA Career Tips, Others, Tutorials, General — admin @ 00:45

DB_ULTRA_SAFE is a new parameter introduced with Oracle 11gR1, and a fantastic new GEM for High Availability, that using Data Guard to configure on both the primary and standby will trigger the most comprehensive data corruption prevention and detection (and repair on 11gR2, see **) tool in the market.

** Starting in Oracle Database 11g Release 2 (11.2), the primary database automatically attempts to repair the corrupted block in real time by fetching a good version of the same block from a physical standby database.

Speaking simple, what this new functionality will do is use your Standby Database as a backup to correct automatically any data corruption on your primary database and vice-versa (again on 11.2).

The DB_ULTRA_SAFE initialization parameter also controls other data protection behavior in Oracle Database, such as requiring ASM to perform sequential mirror write I/Os.

You basically need to understand that when setting DB_ULTRA_SAFE it will control the behaviour of DB_BLOCK_CHECKING, DB_BLOCK_CHECKSUM, or DB_LOST_WRITE_PROTECT parameters for you, which mean:

When you set DB_ULTRA_SAFE to Then the following parameters…
DATA_AND_INDEX (recommended by Oracle)
  • DB_BLOCK_CHECKING is set to FULL.
  • DB_LOST_WRITE_PROTECT is set to TYPICAL.
  • DB_BLOCK_CHECKSUM is set to FULL.
DATA_ONLY
  • DB_BLOCK_CHECKING is set to MEDIUM.
  • DB_LOST_WRITE_PROTECT is set to TYPICAL.
  • DB_BLOCK_CHECKSUM is set to FULL.

Lets’ Check  all the parameters affected by DB_ULTRA_SAFE:

  • DB_BLOCK_CHECKING (Introduced with Oracle 8.1.6) prevents memory and data corruptions, but it incurs some performance overhead on every block change.
  • DB_BLOCK_CHECKSUM (Introduced with Oracle 8.1.6) detects redo and data block corruptions and detect corruptions on the primary database and protect the standby database. This parameter requires minimal CPU resources.
  • DB_LOST_WRITE_PROTECT (also introduced with 11gR1) enable or disable a physical standby database to detect lost write corruptions on both the primary and physical standby database.

Important: if you explicitly set the DB_BLOCK_CHECKING, DB_BLOCK_CHECKSUM, or DB_LOST_WRITE_PROTECT parameters in the initialization parameter file, then the DB_ULTRA_SAFE parameter has no effect and no changes are made to the parameter values. Thus, if you specify the DB_ULTRA_SAFE parameter, do not explicitly set these underlying parameters.

To activate it, all you need to do is follow the following steps:

On the Primary Database:  

  1. Set the DB_ULTRA_SAFE=DATA_AND_INDEX initialization parameter using:
  2. SQL> alter system set db_ultra_safe=dta_and_index scope=spfile;
  3. SQL> shutdown immediate (Shutdown your Database)
  4. SQL> startup (This will start your primary Database using your new parameter set in the SPFILE previously)

On the Physical Standby Database: 

  1. Set the DB_ULTRA_SAFE=DATA_AND_INDEX initialization parameter using:
  2. SQL> alter system set db_ultra_safe=dta_and_index scope=spfile;
  3. SQL> startup nomount
  4. SQL> alter database mount standby database;
  5. SQL> alter database recover managed standby database disconnect from session;

If you are using your Standby Database on Read Only mode you also need to run the follow commands on your Physical Standby DB: 

  1. SQL> alter database recover managed standby database cancel;
  2. SQL> alter database open read only;

If you decide to change later the Read Only Standby to Standby again, you just will need to run the following command: 

  1. SQL> alter database recover managed standby database disconnect from session;

Hoping this information could help you in the future,

Francisco Munoz Alvarez

Example done on primary:

Screen 1

Example done at the Standby:

Screen 2

Technorati Tags: ,,,

Next Page »

Powered by WordPress