Tuesday, June 30, 2015

ODBC The Open Database Connectivity

What is ODBC and where does it come from?

ODBC (Open Database Connectivity) provides a way for client programs (eg Visual Basic, Excel, Access, Q+E etc) to access a wide range of databases or data sources.
ODBC is a standardized API, developed according to the specifications of the SQL Access Group, that allows one to connect to SQL databases. It defines a set of function calls, error codes and data types that can be used to develop database independent applications.
ODBC is usually used when database independence or simultaneous access to different data sources is required.

What is the difference between ODBC and Net8?

ODBC is an industry standard way to connect to SQL databases like Oracle, SQL Server and DB2. Net8 or SQL*Net is an Oracle proprietary standard connection protocol that only works with Oracle databases. The fact that it is proprietary usually means that it is slightly faster, better integrated with Oracle and more feature rich.
Most ODBC to Oracle implementations require the ODBC software stack to run on top of the Oracle Net8 software stack.

Are there alternative products that can be used?

Yes, look at Oracle Objects for OLE, JDBC and Net8.

What do I need to get ODBC to work?

You typically need the following:
  • A workstation with TCP/IP connectivity
  • An Oracle ODBC driver
  • Oracle's SQL*Net or Instant Client software

Where can one get ODBC drivers for Oracle and Rdb?

Oracle's ODBC drivers can be downloaded free of charge from Oracle Technet.
If you are still using Oracle V6, you can use the ODBC driver that comes with Microsoft Access 1.1 or an equivalent driver from whatever source.
Since ODBC is a standard, there are alternative drivers available via other vendors. The following vendors provide ODBC drivers that can run from Windows and Unix:
Note: If you plan to use a 16-bit application with ODBC (even if it is running on Windows95 or Windows NT), you will need to use a 16-bit Windows 3.1 ODBC driver.

Do I need SQL*Net to connect to Oracle via ODBC?

For Oracle's ODBC drivers, YES.
Some multi-tier ODBC drivers (eg. Openlink and Visionware) do not require SQL*Net on the client as one has to install an 'ODBC server component' on the server. The ODBC drivers then use the underlying network protocol (eg. TCP/IP) without using SQL*Net.

How do I create a Data Source?

A data source is a logical name for a data repository or database. To define a data source, open the ODBC manager by double clicking on the ODBC icon in the Control Panel. Select the "add" button, then select the ODBC Driver for the database you want to connect to. The data source definition screen will appear. Define the data source name and other information as it pertains to your configuration.

What ODBC Conformance Level is supported by Oracle?

ODBC provides 4 conformance levels depending upon how much of the ODBC specification is implemented in the driver. The levels are:
  • CORE API
  • LEVEL 1
  • LEVEL 2
  • LEVEL 3 - latest spec.
The Oracle7 ODBC driver supports ODBC Version 2.5 and 3.0 Level 2 only.
Oracle does not support Level 3 ODBC, but Level 1 is all that is necessary to do standard operations. If you develop applications that will run on different databases, you might want to limit yourself to level 1 ODBC calls.

Should I give ODBC to my end-users?

It all depends... for performance reasons I would not allow end-users to access an OLTP (On-line Transaction Processing) system via ODBC. Rather, setup a Data Warehouse or Data Mart and let users enter their "queries from hell" against that database.

How secure is ODBC?

Any ODBC sniffer will be able to trace everything from an ODBC perspective. This includes data, usernames, passwords etc. However, if you are using an ODBC driver that provides encryption, you can increase your level of security.
Since any front-end tool can effectively connect to and modify your databases, you need to enforce security at the server level.
On the other hand, if you use TCP/IP, ODBC security should be the least of your concerns!

How fast is ODBC?

According to Oracle, their ODBC driver, on average, runs about 3% slower than native Oracle access. My experience, however, is that ODBC can be extremely slow!!! the performance depends very much on the query application that you use on the client side. Much of the query tools supply more options than plain SQL. to perform these queries first all data is transported over the network to your client. This you should avoid. When you create queries that fit within regular SQL the query is processed on the server and only the result is transported over the network. This is very fast. But you have to always be aware of the kind of SQL that is made by your front end tool.
Note: ODBC is a programming interface, not an implementation. Performance depends on the implementation of the interface. There are several types of ODBC drivers for Oracle. Here's a white paper with benchmarks comparing OCI and ODBC performance: http://www.datadirect.com/docs/public/whitepapers/wp-odbcvsoci.pdf

How can I test if ODBC is setup correctly?

Execute the ODBCTST.EXE program that comes with your ODBC driver to ensure that all your connections are properly configured and that you can connect to your data source.

How can I trace ODBC calls?

The Microsoft ODBC Administrator (My Computer/ Control Panel/ ODBC) provides a simple ODBC call trace that logs ODBC calls to a file. To use this facility, click the Options button on the initial Data Sources form. Check the box labeled "Trace ODBC Calls" and change the default log filename (SQL.LOG) if desired. The underlying ODBC calls the front-end application makes to communicate with the ODBC Driver will be logged to this file.
Specialized ODBC trace programs, such as Microsoft's ODBC Spy (included in the ODBC SDK 2.0), ODBC Inspector and ODBC Agent can be used to capture detailed ODBC call information and the return code for each call.

How do I tell which driver version I have installed?

Run the ODBC administrator from the desktop (ODBCADM.EXE or ODBCAD32.EXE):
  • Click the "Drivers" button
  • Choose the desired ODBC driver
  • Click the "About" button
Version information will be displayed for the selected driver.

What is SQLPASSTHROUGH?

Use the ODBC SQLPASSTHROUGH option when you need to pass your SQL statement to the ODBC data source directly. No massaging or local processing is done on the statement, it is passed to the database server AS IS. This improves performance, but the resulting dynaset is not updatable. Example:
db.ExecuteSQL("BEGIN procedurename(param1,param2,param3); END;", SQLPASSTHROUGH)

How does one attach an Oracle table in MS-Access?

Create a linked table under the table tab in Access. Right click; select link table. A dialog box opens, at the bottom, change the "files of type" box to ODBC Databases. This will open the Data Source dialog box. Select your data source, file or machine (note the type you created earlier). You will now be prompted to login to the Oracle database.
One can also link a table programmatically. Open a new MODULE in Access, add this code to it and RUN (F5):
Option Compare Database
Option Explicit

Function AttachTable() As Variant
  On Error GoTo AttachTable_Err

  Dim db As Database
  Dim tdef As TableDef
  Dim strConnect As String

  Set db = CurrentDb()
  strConnect = "ODBC;DSN=oraweb;DBQ=qit-uq-cbiw_oraweb;DATABASE="
  ' NOTE: DSN is your ODBC Data Source Name; DBQ is your TNSNAMES.ORA entry name

  Set tdef = db.CreateTableDef("MY_ACCESS_TABLENAME")
  ' tdef.Attributes DB_ATTACHEDODBC
  tdef.Connect = strConnect
  tdef.SourceTableName = "MY_ORACLE_TABLENAME"
  db.TableDefs.Append tdef
 
AttachTable_Exit:
  Exit Function
 
AttachTable_Err:
  MsgBox "Error: " & Str(Err) & " - " & Error$ & " occured in global module."
  Resume AttachTable_Exit

End Function

How does one get Oracle data into MS-Excel?

There are several ways to extract data from Oracle and load it into Microsoft Excel. Here are some:
SQL*Plus
The easiest method is to spool the data from sqlplus to a CSV formatted file and open it in MS-Excel. Here is an example:
set echo off pagesize 0 head off feed off veri off trimspool on
spool data.csv
select COL1 || ',' || COL2 || ',' || COL3 ....
spool off
The resulting spool file (data.csv in our exampel) can now be copied to a Windows machine and opened in Excel.
OO4O
Oracle Objects for OLE (OO4O) can be used to load data into Excel. For more details, see the OO4O FAQ.
3rd Party Tools
  • SQL*XL Lite - a freeware plug-in used to run SQL statements directly from Excel. SQL*XL (formerly Oraxcel) requires OO4O to be installed on your PC.
  • Fastreader - from wisdomforce
  • FlexTracer - 3rd party ODBC tracer
  • IRI FACT (Fast Extract) - from IRI, The CoSort Company, which uses OCI and parallelism to produce CSV files

Excel will also directly read HTML-formatted tables, which can easily be generated from sqlplus. For example, consider the following SQL script:
C:\>type htmlobjects.sql
set pages 0 lin 32767 feedback off verify off heading off trims on
alter session set nls_date_format = "RRRR/MM/DD HH24:MI";
select '<table>' from dual;
select '<tr><td>' ||
        object_name ||
       '</td><td>' ||
       object_type ||
       '</td><td>' ||
       created ||
       '</td></tr>'
from all_objects
where rownum < 10;
select '</table>' from dual;
Running this script from sqlplus gives you a table:
SQL> spool objects.html
SQL> start htmlobjects
<table>
<tr><td>I_ICOL1</td><td>INDEX</td><td>1996/05/10 10:25</td></tr>
<tr><td>_NEXT_OBJECT</td><td>NEXT OBJECT</td><td>1996/05/10 10:25</td></tr>
<tr><td>CDEF$</td><td>TABLE</td><td>1996/05/10 10:25</td></tr>
<tr><td>TAB$</td><td>TABLE</td><td>1996/05/10 10:25</td></tr>
<tr><td>IND$</td><td>TABLE</td><td>1996/05/10 10:25</td></tr>
<tr><td>C_FILE#_BLOCK#</td><td>CLUSTER</td><td>1996/05/10 10:25</td></tr>
<tr><td>CLU$</td><td>TABLE</td><td>1996/05/10 10:25</td></tr>
<tr><td>I_COBJ#</td><td>INDEX</td><td>1996/05/10 10:25</td></tr>
<tr><td>I_USER#</td><td>INDEX</td><td>1996/05/10 10:25</td></tr>
</table>
SQL> quit

Migrate the Microsoft Access Database to Oracle

To migrate the Microsoft Access database to Oracle:
  1. Start Oracle SQL Developer version 1.2.0 or later. For example:
    1. Create an Oracle user named MIGRATIONS with the default tablespace USER and temporary tablespace TEMP and grant it at least RESOURCE, CREATE SESSION, and CREATE VIEW privileges.
    2. Create a database connection named Migration_Repository that connects to the MIGRATIONS user.
    3. Right-click the connection, select Migration_Repository, and then select Migration Repository and then Associate Migration Repository to create the repository.
  2. Load the database metadata (.xml file) created in step 1. Select Migration and then Capture Microsoft Access Exported XML.
    This captures the schema and creates a Captured Model of the Microsoft Access database.
  3. Convert the captured database schema to Oracle. Right-click Captured Model and select Convert to Oracle Model.
  4. Generate the migrated Oracle database schema. Right-click Converted Model and select Generate.
    The generated DDL statements should execute against your Oracle database instance, to generate the migrated schema objects.

Thursday, June 25, 2015

Oracle Reports -Performance Tuning tips --Part2

Column Aliasing When writing queries in Oracle Reports, always specify column aliases to keep column names clear and readable. This is extremely useful when future modifications are required to the Data Model. The reason is that the Layout model is driven by the Data model, so any changes in the Data model will cascade down to the Layout model. Using column aliases, protects the Layout model (to a certain degree), from such changes.

Summary, Formula and Placeholder columns Apart from columns which are selected from the database, there are other types of columns which can be created within the report itself. They are SUMMARY columns, FORMULA columns, and PLACEHOLDER columns.
In brief: A SUMMARY column allows you to perform aggregate functions such as SUM, AVG, COUNT, MAX, MIN etc.. A FORMULA column allows you to perform any pl/sql function that will return a value of type NUMBER, VARCHAR2, DATE or BOOLEAN.
 However columns referenced in the formula must be in the same group or at a higher level, due to frequency constraints

 A PLACEHOLDER column is merely a container, or a “place” to “hold” a value. A formula column is used to populate a placeholder column.
Where do these columns go? In which group do they belong? The answers are simple.

If you want to get the total number of employees in a department, the sum must reset at department level, so the SUMMARY column must be created in the department group.

If you want to calculate the commission in dollars for each employee, that is salary times commission percentage, the FORMULA column must be created in the same group as the salary and commission percentage columns, that is the employee group.

 If you want to create a PLACEHOLDER column, or container into which values are assigned, place it in the same group as the formula column which is performing the assignment, or place it at a higher level.

When creating these types of columns, always use the default naming convention. This can save precious hours later if and when the report needs to be modified. For example: Summary column names are prefixed by CS_ Formula column names are prefixed by CF_ Placeholder columns names are prefixed by CP_
If possible try to calculate summary functions and formulae directly in the database, this will be more efficient compared to querying all the records from the server to the client and performing the calculations on the client side.
System Parameters and User Parameters These parameters also fall under the Data Model umbrella. They can be viewed from the Object Navigator, not from the Data Model window. Why do these parameters belong to the Data Model? Because they represent DATA that is required to run the report. For example, some of the System Parameters are DESTYPE (File, Printer, Mail etc.), DESNAME (Output filename, Printer name, Email address etc.), MODE (Character, Bitmap), ORIENTATION (Portrait, Landscape), DESFORMAT (PDF, HTMLCSS, etc.) and so on. The User Parameters are entirely custom created and can be of type VARCHAR2, NUMBER or DATE. These types of parameters are required in conjunction with the Runtime Parameter Form which will be discussed later on in this paper.
System Variables These are default variables such as Current Date or Physical Page Number, a list of which is found in the Source property of a field.

Global Variables These can be very useful when you need to assign values to variables in “mid-flight”, for example in the Between Pages Trigger or in a format trigger. To create a global variable, simply create a local PL/SQL program unit of type Package Spec, then declare a variable in it with the appropriate datatype. A Package Body is not required.

To assign values to this global variable, use the following syntax: package_spec_name.variable_name.
For example if the package spec is called Global and the variable declared in it is called v_Count, then in the report trigger or format trigger, we can assign a value to it as follows

:global.v_count := 10;

Page Breaks

Page Breaks Always use the “Maximum Records per Page” property on the appropriate Repeating Frame, to control page breaks. For example, if every new department must begin on a new page, go to the Department repeating frame and set the Maximum Records per Page property to 1.
Alternatively, if there is a requirement such as: “If a new department begins half way down the page and all the employees of that department cannot fit on the same page, then move the entire department to the start of the next page.” .. this is achieved by setting the Page Protect property on the department frame.

Oracle Reports -Performance Tuning tips --Part2

Column Aliasing When writing queries in Oracle Reports, always specify column aliases to keep column names clear and readable. This is extremely useful when future modifications are required to the Data Model. The reason is that the Layout model is driven by the Data model, so any changes in the Data model will cascade down to the Layout model. Using column aliases, protects the Layout model (to a certain degree), from such changes.

Summary, Formula and Placeholder columns Apart from columns which are selected from the database, there are other types of columns which can be created within the report itself. They are SUMMARY columns, FORMULA columns, and PLACEHOLDER columns.
In brief: A SUMMARY column allows you to perform aggregate functions such as SUM, AVG, COUNT, MAX, MIN etc.. A FORMULA column allows you to perform any pl/sql function that will return a value of type NUMBER, VARCHAR2, DATE or BOOLEAN.
 However columns referenced in the formula must be in the same group or at a higher level, due to frequency constraints

 A PLACEHOLDER column is merely a container, or a “place” to “hold” a value. A formula column is used to populate a placeholder column.
Where do these columns go? In which group do they belong? The answers are simple.

If you want to get the total number of employees in a department, the sum must reset at department level, so the SUMMARY column must be created in the department group.

If you want to calculate the commission in dollars for each employee, that is salary times commission percentage, the FORMULA column must be created in the same group as the salary and commission percentage columns, that is the employee group.

 If you want to create a PLACEHOLDER column, or container into which values are assigned, place it in the same group as the formula column which is performing the assignment, or place it at a higher level.

When creating these types of columns, always use the default naming convention. This can save precious hours later if and when the report needs to be modified. For example: Summary column names are prefixed by CS_ Formula column names are prefixed by CF_ Placeholder columns names are prefixed by CP_
If possible try to calculate summary functions and formulae directly in the database, this will be more efficient compared to querying all the records from the server to the client and performing the calculations on the client side.
System Parameters and User Parameters These parameters also fall under the Data Model umbrella. They can be viewed from the Object Navigator, not from the Data Model window. Why do these parameters belong to the Data Model? Because they represent DATA that is required to run the report. For example, some of the System Parameters are DESTYPE (File, Printer, Mail etc.), DESNAME (Output filename, Printer name, Email address etc.), MODE (Character, Bitmap), ORIENTATION (Portrait, Landscape), DESFORMAT (PDF, HTMLCSS, etc.) and so on. The User Parameters are entirely custom created and can be of type VARCHAR2, NUMBER or DATE. These types of parameters are required in conjunction with the Runtime Parameter Form which will be discussed later on in this paper.
System Variables These are default variables such as Current Date or Physical Page Number, a list of which is found in the Source property of a field.

Global Variables These can be very useful when you need to assign values to variables in “mid-flight”, for example in the Between Pages Trigger or in a format trigger. To create a global variable, simply create a local PL/SQL program unit of type Package Spec, then declare a variable in it with the appropriate datatype. A Package Body is not required.

To assign values to this global variable, use the following syntax: package_spec_name.variable_name.
For example if the package spec is called Global and the variable declared in it is called v_Count, then in the report trigger or format trigger, we can assign a value to it as follows

:global.v_count := 10;

Page Breaks

Page Breaks Always use the “Maximum Records per Page” property on the appropriate Repeating Frame, to control page breaks. For example, if every new department must begin on a new page, go to the Department repeating frame and set the Maximum Records per Page property to 1.
Alternatively, if there is a requirement such as: “If a new department begins half way down the page and all the employees of that department cannot fit on the same page, then move the entire department to the start of the next page.” .. this is achieved by setting the Page Protect property on the department frame.

Oracle Reports -Performance Tuning tips

ACCESSING THE DATA
INDEXES
Columns used in the WHERE clause should be indexed.  The impact of indexes used on the columns in the master queries of a report will be minor as these queries will only access the database once.  However,  for a significant performance improvement indexes should be used on any linked columns in the detail query.
A lack of appropriate indexes can result in many full-table scans which can have a major impact on performance.
CALCULATIONS
When performing calculations within a report (either through summary or formula columns), the general rule of thumb is the more calculations that can be performed within the SQL of the report queries, the better. If the calculations are included in the SQL, then they are performed before the data is retrieved by the database, rather than the performed on the retrieved data by the Report. Database-stored user-defined PL/SQL functions can also be included in the query select list. This is more efficient then using a local PL/SQL function (e.g. in a formula column), since the calculated data is returned as part of the result set from the database.

TO LINK OR NOT TO LINK
As with most operations in Reports, there are a number of ways to create data models that include more than one table. Consider, for example, the standard case of the dept/emp join, i.e., the requirement is to create a report that lists all the employees in each department in the company. In Reports the user can either use the following in a single query:
Select d.dname, e.ename From emp e, dept d Where e.deptno(+) = d.deptno
Or they can create two queries
Select deptno, dname from dept Select deptno, ename from emp
and create a column link between the two on deptno.
When designing the data model in the report, it is preferable to minimize the actual number of queries by using fewer, larger (multi-table) queries, rather than several simpler (single-table) queries. Each time a query is issued, Oracle Reports needs to parse, bind and execute a cursor. A single query report is therefore able to return all the required data in a single cursor rather than many. Also be aware that with master-detail queries, the detail query will be re-parsed, re-bound and re-executed for each master record retrieved. In this instance it is often more efficient to merge the two queries and use break groups to create the master-detail effect.
It should be noted, however, that the larger and more complex a query gets, the more difficult it can be to maintain. Each site needs to decide at what point to balance the performance versus the maintenance requirements.

LAYOUT

When generating a default layout Oracle Reports puts a frame around virtually every object, so that it is protected from being overwritten when the report is run.
At runtime, every layout object (frames, fields, boilerplate, etc.) is examined to determine the likelihood of that object being overwritten. In some situations (for example boilerplate text column headings), there is clearly no risk of the objects being overwritten and hence the immediately surrounding frame can be removed.
This reduces the number of objects that Oracle Reports has to format and hence improves performance.
Similarly, when an object is defined as having an undefined size (variable, expanding or contracting in either or both the horizontal and vertical directions) then extra processing is required since Oracle

Reports must determine that instance of the object's size before formatting that object and those around it. If this sizing can be set to fixed then this additional processing is not required, since the size and positional relationships between the objects is already known.

Furthermore, instead of truncating a character string from a field in the Report Builder Layout, it is better to use the SUBSTR function in the report query to truncate the data at the database level  This reduces unnecessary processing and formatting after the data retrieval.

FORMAT TRIGGERS
Format triggers have two major purposes:
• Dynamically disable and enable objects at runtime.
• Dynamically change the appearance of an object at runtime.
Care should always be exercised when using format triggers, since the triggers do not only fire for every instance of their associated object produced, but every time the object is formatted at runtime.
These two scenarios may sound the same, but consider the following situation:
A tabular report includes a single repeating frame that can expand vertically and has page protect set on. As this report is formatted, there is room for one more line at the bottom of the first page.

 Reports starts to format the next instance of the repeating frame and fires its associated format trigger. One of the objects inside the repeating frame is found to have expanded and this instance of the repeating frame is therefore moved to the following page and the format trigger for the repeating frame is fired again. Hence, although the repeating frame only appears once (at the top of the second page), the format trigger has fired twice.

Because you can not be sure how many times a format trigger will fire for a particular object,  DML should not be performed in a format trigger.  With the example above, had the format trigger contained an INSERT statement then two rows of data would have been inserted.
GENERAL LAYOUT GUIDELINES
The following guidelines can improve performance when creating or changing a report layout:

• Make your non-graphical layout objects (e.g. boilerplate text or fields with text) fixed in size -- that is, set the Vertical and Horizontal Elasticity property of the field to Fixed. In particular, making repeating frames and their contents fixed in size can improve performance. Non- graphical objects that are variable in size require more processing because Report Builder must determine their size before formatting them. Non-graphical objects that are fixed in size do not require this additional processing because their size is already known.

• Make your graphical layout objects (e.g., images and Oracle Graphics objects) variable in size -- that is, Vertical and Horizontal Elasticity of Variable. Graphical objects that are fixed in size usually need to have their contents scaled to fit inside of the object. Scaling an object's contents requires more processing. If the object is variable in size, it can grow or shrink with the contents and scaling is not necessary.

• Specify Reduce Image Resolution for image objects whose size you reduce. (This option is available as a drawing option under the Format menu). When you reduce the size of an image, it requires less information to display it than when it was larger. Reduce Image Resolution eliminates the unnecessary information and reduces the amount of space needed to store the image. This can be particularly useful for large, multi-colored images.

• Make fields that contain text one line long and ensure that their contents fit within their specified width (e.g., by using the SUBSTR function). If a field with text spans more than one line, then Report Builder must use its word-wrapping algorithm to format the field. Ensuring that a field only takes one line to format avoids the additional processing of the word-wrapping algorithm.

• Minimize the use of different formatting attributes (e.g., fonts) within the same field or boilerplate text. If text in a field or boilerplate object contains numerous different formatting attributes, it requires longer to format.

Sql Perfomance tuning Technics

Watch Indexed WHERE Conditions
Assume index on address (city, state)

Non-leading index column references cannot use indexes
Where state = 'AP'     [Index Not used]
Where city = 'NELLORE'    [Index Used]

Where state = 'AP' and city = 'NELLORE'   [Index Used]
NOT, != and <> disable index use
Where state not in ('AP', 'TN','UP'')   [Index Not used]
Where state! = 'AP'    [Index Not used]

NULL value references can never use indexes
Where state IS NULL    [Index Not used]
Where state IS NOT NULL    [Index Not used]

Expression references can never use indexes
Where substr(city,1,3) = 'NELLORE'    [Index Not used]
Where city like 'NELLORE%'    [Index Used]

Where city || state = 'NELLOREAP'   [Indx Not used]
Where city = 'DALLAS' and state = 'AP‘   [Index Used]

Where salary * 12 >= 24000    [Index Not used]
Where salary >= 2000    [Index Used

SQL Performance Tuning-Nested Queries

Nested Subqueries
Using nested sub queries instead of joining tables in a single query can lead to dramatic performance gains. Only certain queries will meet the criteria for making this modification. When you find the right one, this trick will take performance improvement to an exponentially better height.  The conditions for changing a query to a nested sub query occur when:
Tables are being joined to return the rows from ONLY one table.
Conditions from each table will lead to a reasonable percentage of the rows to be retrieved (more than 10%)
The original query:
SELECT     A.COL1, A.COL2
FROM     TABLE1 A, TABLE2 B
WHERE     A.COL3 = VAR
AND     A.COL4 = B.COL1
AND     B.COL2 = VAR;

The new query:
SELECT     A.COL1, A.COL2
FROM     TABLE1 A
WHERE     A.COL3 = VAR
AND     EXISTS
(SELECT     ‘X’
FROM     TABLE B
WHERE     A.COL4 = B.COL1
AND     B.COL2 = VAR);

A real life example:
SELECT    ORDER.ORDNO, ORDER.CUSTNO
FROM    ORDER_LINE OL, ORDER
WHERE    ORDER.ORDNO = OL.ORDNO
AND    ORDER.CUSTNO = 5
AND     OL.PRICE = 200;

Execution Time: 240 Minutes

The solution:
SELECT    ORDNO, CUSTNO
FROM    ORDER
WHERE    CUSTNO = 5
AND EXISTS
(SELECT     ‘X’
FROM     ORDER_LINE OL
WHERE     ORDER.ORDNO = OL.ORDNO
AND OL.PRICE = 200);

SQL Tuning Technics-Recursive Procedures

SQL Parsing in Recursive Procedures
Reduce the parse-to-execution ratio in your applications.
Description: Extensive SQL parsing can become a serious problem for a heavily loaded Oracle instance. This is especially true if a SQL statement executed many times is also parsed many times. There are a number of standard techniques and guidelines, which help reduce unnecessary parsing. In some special cases, though, even following all the guidelines does not save you from extensive parsing. Find out below how to apply a workaround in a specific situation to further reduce the parse-to-execute ratio of a statement.
The effect can be observed when a SQL cursor is used in a recursively-structured procedure. In such procedures, very often a cursor is opened and for each fetched row the same procedure is called, which opens the same cursor, etc. In most of the cases the recursive call is executed before the cursor is closed. As a result of this, for each new "cursor open" a parse call is executed resulting in as many parses as executions.
Take a look at a simplified recursive procedure using the SCOTT schema:

PROCEDURE recurs (p_mgr IN emp.mgr%TYPE)
IS
    CURSOR emp_mgr IS
    SELECT empno
    FROM emp
    WHERE mgr = p_mgr;

BEGIN
    FOR c IN emp_mgr
    LOOP
        recurs(c.empno);
    END LOOP;
END recurs;
As you can see the recursive call is executed before the (implicit) cursor is closed. The main idea for reducing the parse calls is to first collect the results of the cursor (for example in a PL/SQL table), then close the cursor and finally cycle through the results and perform the recursive procedure calls.
See below and example of such procedure (In this procedure I have used a bulk bind select, but a normal cursor loop can be used too):

PROCEDURE recurs_close (p_mgr IN emp.mgr%TYPE)
IS
    CURSOR emp_mgr IS
    SELECT empno
    FROM emp
    WHERE mgr = p_mgr;
    TYPE t_empno IS TABLE OF NUMBER(4) INDEX BY BINARY_INTEGER;
    p_empno t_empno;
    i PLS_INTEGER := 0;
BEGIN

    OPEN emp_mgr;
    FETCH emp_mgr BULK COLLECT INTO p_empno;
    i := emp_mgr%ROWCOUNT;
    CLOSE emp_mgr;
    FOR j IN 1..i
    LOOP
        recurs_close(p_empno(j));
    END LOOP;
END recurs_close;
In the excerpts of the trace files generated during the procedure execution can be seen that the first procedure has as many parses as executions (14), while the second has 1 parse only.


exec cursor_parse.recurs(7839);

SELECT empno
    FROM emp
    WHERE mgr = :b1


call     count    cpu    elapsed    disk      query    current rows
------- ------  ----- ---------- ------- ---------- ---------- ----------
Parse       14   0.02       0.15       0          0          0 0
Execute     14   0.00       0.00       0          0          0 0
Fetch       27   0.00       0.05       1         26         28 13
------- ------  ----- ---------- ------- ---------- ---------- ----------
total       55   0.02       0.20       1         26         28 13


exec cursor_parse.recurs_close(7839);

SELECT empno
    FROM emp
    WHERE mgr = :b1


call    count    cpu     elapsed  disk  query  current rows
------- -----  ---- -------  ----  -----  ------- --------
Parse       1     0.00    0.00     0      0        0 0
Execute    14   0.00    0.00     0      0        0 0
Fetch      14     0.00    0.00     0     14       28 13
------- -----  ---- ------- ----- ------ -------- --------
total      29  0.00    0.00     0     14       28 13

Most of the important statistics are better for the execution of the recurs_close than the recurs procedure.

Statistic name                          recurs  recurs_close
opened cursors cumulative           26      12
recursive calls                                               89      50
session logical reads                       84      72
consistent gets                            41      29
no work - consistent read gets          32      20
cursor authentications                        2       1
parse count (total)                        26      12

oracle tuning tips

Watch Non-Indexed WHERE Conditions
Oracle evaluates Non-Indexed conditions linked by AND bottom up
Bad: select * from address where
                         areacode = 500003 and
                         type_nr = (select seq_nr from code_table where type = ‘HOME’)
Good: select * from address where
                         type_nr = (select seq_nr from code_table where type = ‘HOME’) and
                         areacode = 500003
Oracle evaluates Non-Indexed conditions linked by OR top down
Bad: select * from address where
                         type_nr = (select seq_nr from code_table where type = ‘HOME’) or
                         areacode = 500003
Good: select * from address where
                         areacode = 500003 or
                         type_nr = (select seq_nr from code_table where type = ‘HOME’)
Oracle Tuning Tips UNION/OR
Consider IN or UNION in place of OR  

i
 columns are not indexed, stick with OR
if columns are indexed, use IN or UNION in place of OR
IN example
Bad: select * from address where
                         state = 'AP‘ or
                         state = 'KL‘ or
                         state = 'KL‘
Good: select * from address where
                         state in ('AP','KL','KL')
UNION example
Bad: select * from address where
                         state = ‘KL’ or
                         areacode = 500003
Good: select * from address where
                         state = ‘KL’
               union
               select * from address where
                         areacode = 500003

Bulk Collect In Oracle

BULK COLLECT

Ø  This is used for array fetches
Ø  With this you can retrieve multiple rows of data with a single roundtrip.
Ø  This reduces the number of context switches between the pl/sql and sql engines.
Ø  Reduces the overhead of retrieving data.
Ø  You can use bulk collect in both dynamic and static sql.
Ø  You can use bulk collect in select, fetch into and returning into clauses.
Ø  SQL engine automatically initializes and extends the collections you reference in the bulk collect clause.
Ø  Bulk collect operation empties the collection referenced in the into clause before executing the query.
Ø  You can use the limit clause of bulk collect to restrict the no of rows retrieved.
Ø  You can fetch into multible collections with one column each.
Ø  Using the returning clause we can return data to the another collection.

BULK COLLECT IN FETCH

Ex:
DECLARE
     Type t is table of dept%rowtype;
     nt t;
     Cursor c is select *from dept;
BEGIN
     Open c;
     Fetch c bulk collect into nt;
     Close c;
     For i in nt.first..nt.last loop
           dbms_output.put_line('Dname = ' || nt(i).dname || ' Loc = ' || nt(i).loc);
     end loop;
END;

Output:
Dname = ACCOUNTING Loc = NEW YORK
Dname = RESEARCH Loc = DALLAS
Dname = SALES Loc = CHICAGO
Dname = OPERATIONS Loc = BOSTON

BULK COLLECT IN SELECT

Ex:
DECLARE
     Type t is table of dept%rowtype;
     Nt t;
BEGIN
     Select * bulk collect into nt from dept;
     for i in nt.first..nt.last loop
           dbms_output.put_line('Dname = ' || nt(i).dname || ' Loc = ' || nt(i).loc);
     end loop;
END;

Output:
Dname = ACCOUNTING Loc = NEW YORK
Dname = RESEARCH Loc = DALLAS
Dname = SALES Loc = CHICAGO
Dname = OPERATIONS Loc = BOSTON

LIMIT IN BULK COLLECT

Ex:
DECLARE
     Type t is table of dept%rowtype;
     nt t;
     Cursor c is select *from dept;
BEGIN
     Open c;
     Fetch c bulk collect into nt limit 2;
     Close c;
     For i in nt.first..nt.last loop
           dbms_output.put_line('Dname = ' || nt(i).dname || ' Loc = ' || nt(i).loc);
     end loop;
END;

Output:
Dname = ACCOUNTING Loc = NEW YORK
Dname = RESEARCH Loc = DALLAS

Oracle Parametrized Cursors

Oracle Parametrized Cursors

  •   This was used when you are going to use the cursor in more than one place with different values for the same where clause.
  •   Cursor parameters must be in mode.
  •   Cursor parameters may have default values.
  •   The scope of cursor parameter is within the select statement.
Ex:
     DECLARE
         cursor c(dno in number) is select * from dept where deptno = dno;
         v_dept dept%rowtype;
      BEGIN
         open c(20);
         loop
             fetch c into v_dept;
             exit when c%notfound;
            dbms_output.put_line('Dname = ' || v_dept.dname || ' Loc = ' || v_dept.loc);
         end loop;
         close c;
     END;
Output:
     Dname = RESEARCH Loc = DALLAS
PACKAGED CURSORS WITH HEADER IN SPEC AND BODY IN PACKAGE BODY
  •   cursors declared in packages will not close automatically.In packaged cursors you can modify the select statement without making any changes to the cursor header in the package specification.
  • Packaged cursors with must be defined in the package body itself, and then use it as global for the package.You can not define the packaged cursor in any subprograms.
  •   Cursor declaration in package with out body needs the return clause.
  • Ex:
CREATE OR REPLACE PACKAGE PKG IS
                         cursor c return dept%rowtype is select * from dept;
                procedure proc is
END PKG;
CREATE OR REPLACE PAKCAGE BODY PKG IS
      cursor c return dept%rowtype is select * from dept;
PROCEDURE PROC IS
BEGIN
      for v in c loop
           dbms_output.put_line('Deptno = ' || v.deptno || ' Dname = ' || v.dname || '   
                                                  Loc = ' || v.loc);
      end loop;
END PROC;
END PKG;
Output:
SQL> exec pkg.proc
        Deptno = 10 Dname = ACCOUNTING Loc = NEW YORK
        Deptno = 20 Dname = RESEARCH Loc = DALLAS
        Deptno = 30 Dname = SALES Loc = CHICAGO
                  Deptno = 40 Dname = OPERATIONS Loc = BOSTON
CREATE OR REPLACE PAKCAGE BODY PKG IS
      cursor c return dept%rowtype is select * from dept where deptno > 20;
PROCEDURE PROC IS
BEGIN
      for v in c loop
           dbms_output.put_line('Deptno = ' || v.deptno || ' Dname = ' || v.dname || '   
                                                  Loc = ' || v.loc);
      end loop;
END PROC;
END PKG;
Output:
SQL> exec pkg.proc
               Deptno = 30 Dname = SALES Loc = CHICAGO
                  Deptno = 40 Dname = OPERATIONS Loc = BOSTON