Thursday, 15 October 2020

Access Path

 Full Table Scan:
-------------------------------------------------
select * from sales;
select * from sales where amount_sold > 1770;
select * from employees where employee_id > 100;
 
explain plan for
select * from employees e, departments d
where e.employee_id = d.manager_id;
select * from table (dbms_xplan.display());
 
explain plan for
select * from employees e, departments d
where e.department_id = d.department_id;
select * from table (dbms_xplan.display());
 
Table Access by ROWID
-------------------------------------------------
 
select * from sales where prod_id = 116 and cust_id = 100090;
select * from sales where rowid = 'your_row_id';
create index prod_cust_ix on sales (prod_id,cust_id);
select prod_id,cust_id from sales where prod_id = 116;
drop index prod_cust_ix;
 
Index Range Scan
-------------------------------
It can be applied to both b-tree and bitmap index types
 
-- One side bounded searched
SELECT * FROM SALES WHERE time_id > to_date('01-NOV-01','DD-MON-RR');
 
-- Bounded by both sides
SELECT * FROM SALES WHERE time_id between to_date('01-NOV-00','DD-MON-RR') and to_date('05-NOV-00','DD-MON-RR');
 
-- B-Tree index range scan
SELECT * FROM employees where employee_id > 190;
 
-- Index range scan on Non-Unique Index
SELECT * FROM employees where department_id > 80;
 
-- Order by with the indexed column -  sort is processed
SELECT * FROM employees where employee_id > 190 order by email;
 
-- Order by with the indexed column - no sort is processed
SELECT * FROM employees where employee_id > 190 order by employee_id;
 
-- Index range scan descending
SELECT * FROM employees where department_id > 80 order by department_id desc;
 
-- Index range scan with wildcard
SELECT * FROM PRODUCTS WHERE PROD_SUBCATEGORY LIKE 'Accessories%';
SELECT * FROM PRODUCTS WHERE PROD_SUBCATEGORY LIKE '%Accessories';
SELECT * FROM PRODUCTS WHERE PROD_SUBCATEGORY LIKE '%Accessories%';
 
Index Full Scan
----------------------------------
/* Index usage with order by */
SELECT * FROM departments ORDER BY department_id;
 
/* Index usage with order by, one column of an index - causes index full scan*/
SELECT last_name,first_name FROM employees ORDER BY last_name;
 
/* Index usage with order by, one column of an index - causes unnecessary sort operation*/
SELECT last_name,first_name FROM employees ORDER BY first_name;
 
/* Index usage with order by, but with wrong order - causes unnecessary sort operation */
SELECT last_name,first_name FROM employees ORDER BY first_name,last_name;
 
/* Index usage with order by, with right order of the index - there is no unncessary sort */
SELECT last_name,first_name FROM employees ORDER BY last_name,first_name;
 
/* Index usage with order by, wit unindexed column - there is no unncessary sort */
SELECT last_name,first_name FROM employees ORDER BY last_name,salary;
 
/* Index usage order by - when use * , it performed full table scan */
SELECT * FROM employees ORDER BY last_name,first_name;
 
/* Index usage with group by - using a column with no index leads a full table scan */
SELECT salary,count(*) FROM employees e
WHERE salary IS NOT NULL
GROUP BY salary;
 
/* Index usage with group by - using indexed columns may lead to a index full scan */
SELECT department_id,count(*) FROM employees e
WHERE department_id IS NOT NULL
GROUP BY department_id;
 
/* Index usage with group by - using more columns than ONE index has may prevent index full scan */
SELECT department_id,manager_id,count(*) FROM employees e
WHERE department_id IS NOT NULL
GROUP BY department_id, manager_id;
 
/* Index usage with merge join */
SELECT e.employee_id, e.last_name, e.first_name, e.department_id,
       d.department_name
FROM   employees e, departments d
WHERE  e.department_id = d.department_id;
 
Index Fast Full Scan
-----------------------------------
Since index fast full scan reads the data from the index directly,
and doesn't need to go to the memory to get data, it is the fastest index usage
 
/* Index Fast Full Scan Usage - Adding a different column
    than index has will prevent the Index Fast Full Scan */
SELECT e.employee_id, d.department_id, e.first_name,
       d.department_name
FROM   employees e, departments d
WHERE  e.department_id = d.department_id;
 
/* If all the columns are in the index, it may perform
   an Index Fast Full Scan */
SELECT e.employee_id, d.department_id,
       d.department_name
FROM   employees e, departments d
WHERE  e.department_id = d.department_id;
 
/*Index Fast Full Scan can be applied to b-tree indexes, too
  Even if there is an order by here, it used IFF Scan */
SELECT prod_id from sales order by prod_id;
 
/* Optimizer thinks Index Full Scan is better here*/
SELECT time_id from sales order by time_id;
 
/* Optimizer uses inded Fast Full Scan*/
SELECT time_id from sales;
 
Index Skip Scan
--------------------------
 
/*Index skip scan usage with equality operator*/
SELECT * FROM employees WHERE first_name = 'Alex';
 
/* Index range scan occurs if we use the first column of the index */
SELECT * FROM employees WHERE last_name = 'King';
 
/* Using index skip scan with adding a new index */
SELECT * FROM employees WHERE salary BETWEEN 6000 AND 7000;
CREATE INDEX dept_sal_ix ON employees (department_id,salary);
DROP INDEX dept_sal_ix;
 
/* Using index skip scan with adding a new index
   This time the cost increases significantly */
ALTER INDEX customers_yob_bix invisible;
SELECT * FROM customers WHERE cust_year_of_birth BETWEEN 1989 AND 1990;
CREATE INDEX customers_gen_dob_ix ON customers (cust_gender,cust_year_of_birth);
DROP INDEX customers_gen_dob_ix;
ALTER INDEX customers_yob_bix visible;
 
 
Index Join Scan
-----------------------------
/* Index join scan with two indexes */
SELECT employee_id,email FROM employees;
 
/* Index join scan with two indexes, but with range scan included*/
SELECT last_name,email FROM employees WHERE last_name LIKE 'B%';
 
/* Index join scan is not performed when we add rowid to the select clause */
SELECT rowid,employee_id,email FROM employees;

Hints


/* A query without a hint. It performs a range scan*/

 

SELECT employee_id, last_name

  FROM employees e

  WHERE last_name LIKE 'A%';

 

/* Using a hint to command the optimizer to use FULL TABLE SCAN*/ 

 

SELECT /*+ FULL(e) */ employee_id, last_name

  FROM employees e

  WHERE last_name LIKE 'A%';

 

/* Using the hint with the table name as the parameter*/

 

SELECT /*+ FULL(employees) */ employee_id, last_name

  FROM employees

  WHERE last_name LIKE 'A%';

 

/* Using the hint with the table name while we aliased it*/ 

 

-- If a table has an alias, we cannot use the table name directly. We need to use the alias instead of table names. Otherwise it will not work. 

SELECT /*+ FULL(employees) */ employee_id, last_name

  FROM employees e

  WHERE last_name LIKE 'A%';

 

/* Using an unreasonable hint. The optimizer will not consider this hint */

 

SELECT /*+ INDEX(EMP_DEPARTMENT_IX) */ employee_id, last_name

  FROM employees e

  WHERE last_name LIKE 'A%';

 

/* Using multiple hints. But they aim for the same area. So unreasonable. Optimizer picked full table scan as the best choice */

 

SELECT /*+ INDEX(EMP_NAME_IX) FULL(e)  */ employee_id, last_name

  FROM employees e

  WHERE last_name LIKE 'A%';

 

/* When we change the order of the hints. But it did not change the Optimizer's decision*/

 

SELECT /*+ FULL(e) INDEX(EMP_NAME_IX)   */ employee_id, last_name

  FROM employees e

  WHERE last_name LIKE 'A%';

 

/* There is no hint. To see the execution plan to compare with the next one */ 

 

SELECT 

  e.department_id, d.department_name,

  MAX(salary), AVG(salary)

FROM employees e, departments d

WHERE e.department_id=e.department_id

GROUP BY e.department_id, d.department_name;

 

/* Using multiple hints to change the execution plan */

 

SELECT /*+ LEADING(e d)  INDEX(d DEPT_ID_PK) INDEX(e EMP_DEPARTMENT_IX)*/

  e.department_id, d.department_name,

  MAX(salary), AVG(salary)

FROM employees e, departments d

WHERE e.department_id=e.department_id

GROUP BY e.department_id, d.department_name;

 

/* Using hints when there are two access paths.*/ 

 

SELECT /*+ INDEX(EMP_DEPARTMENT_IX) */ employee_id, last_name

  FROM employees e

  WHERE last_name LIKE 'A%'

  and department_id > 120;

 

/* When we change the selectivity of last_name search, it did not consider our hint.*/

 

SELECT /*+ INDEX(EMP_DEPARTMENT_IX) */ employee_id, last_name

  FROM employees e

  WHERE last_name LIKE 'Al%'

  and department_id > 120;

 

/* Another example with multiple joins, groups etc. But with no hint*/

 

SELECT customers.cust_first_name, customers.cust_last_name,

  MAX(QUANTITY_SOLD), AVG(QUANTITY_SOLD)

FROM sales, customers

GROUP BY customers.cust_first_name, customers.cust_last_name;

WHERE sales.cust_id=customers.cust_id

GROUP BY customers.cust_first_name, customers.cust_last_name;

 

/* Performance increase when performing parallel execution hint*/

 

SELECT /*+ PARALLEL(4) */ customers.cust_first_name, customers.cust_last_name,

  MAX(QUANTITY_SOLD), AVG(QUANTITY_SOLD)

FROM sales, customers

WHERE sales.cust_id=customers.cust_id

No comments: