understanding explain plan in oracle

戏子无情 提交于 2019-12-10 09:25:01

问题


I was trying to understand the explain plan in oracle and wanted to know what conditions oracle considers while forming the explain plan

I was testing a simple query in HR schema present in oracle 11g

select * from countries 
where region_id in (select region_id from regions where region_name = 'Europe');

When I ran the following queries:

explain plan for 
select * from countries 
where region_id in (select region_id from regions where region_name = 'Europe');

SELECT * FROM table(dbms_xplan.display(null,null,'basic'));

I got the following output in the explain table:

--------------------------------------------------------
| Id  | Operation                    | Name            |
--------------------------------------------------------
|   0 | SELECT STATEMENT             |                 |
|   1 |  NESTED LOOPS                |                 |
|   2 |   INDEX FULL SCAN            | COUNTRY_C_ID_PK |
|   3 |   TABLE ACCESS BY INDEX ROWID| REGIONS         |
|   4 |    INDEX UNIQUE SCAN         | REG_ID_PK       |
--------------------------------------------------------

Here I observed that the outer query was executed first, i.e countries table was executed first as indicated by Row 3.

Now I added an index on the region_name of the regions table and ran the explain plan again and got the following output

--------------------------------------------------------------
| Id  | Operation                    | Name                  |
--------------------------------------------------------------
|   0 | SELECT STATEMENT             |                       |
|   1 |  NESTED LOOPS                |                       |
|   2 |   TABLE ACCESS BY INDEX ROWID| REGIONS               |
|   3 |    INDEX RANGE SCAN          | REGIONNAME_REGIONS_IX |
|   4 |   INDEX UNIQUE SCAN          | COUNTRY_C_ID_PK       |
|   5 |    INDEX RANGE SCAN          | COUNTRIES_REGIONID_IX |
--------------------------------------------------------------

Now my question is:

  1. Shouldn't the inner query be executed first irrespective of whether index is present or not
  2. If the adding an index alters the execution plan, what other features can alter it?
  3. In general case what is the execution process like is it sequential (first executes the join which occurs first and then goes to next join in the query) ?

Thanks in advance for your help.

-Varun


回答1:


The explain plan relies heavily on the Cost Based Optimizer (CBO). You can help this process out by gathering statistics on the table(s) you are querying against. Now in terms of why would the index change the plan, that is because you have supplied critical information to the CBO that it did not have before. It is the equivalent of me asking you this question:

No index:
"Where is the street?"

With index:
"Where is the street that has a blue house on it?"

The second question gives greater context and is thus faster for you to deduce and you don't have to enumerate all such things that are streets.

You can supply hints to a query i.e.:

select /*+ parallel */ * from table
to give a hint to run this query in parallel.

For the third question, that I imagine is a bit of the Oracle process and is not documented for the world to consume.

In the first question, no not necessarily, it is all cost based.




回答2:


I don't know if they changed anything in the execution plan outputs in 11g, but are you sure you are showing us the right query? You are selecting all columns (select *) from table countries, but the explain plan does not show any table access? Or does COUNTRY_C_ID_PK include all columns?

I would expect the following plan (without the index):

SELECT
  NESTED LOOP
    FULL TABLE SCAN (regions)
    TABLE ACCESS BY INDEX ROWID (countries)
      INDEX RANGE SCAN (COUNTRIES_REGIONID_IX)

With the index in place, I would expect something like this:

SELECT
  NESTED LOOP
    TABLE ACCESS BY INDEX ROWID (regions)
      INDEX RANGE SCAN (REGIONNAME_REGIONS_IX)
    TABLE ACCESS BY INDEX ROWID (countries)
      INDEX RANGE SCAN (COUNTRIES_REGIONID_IX)

For your questions:

  1. Oracle may drive the query from the inner or outer query as it sees fit depending on the available statistics
  2. There are soo many things that influence the execution plan...
  3. Oracle can only join two tables (or row sources) at a time. The result of a join is also a row source that can be joined to the next table



回答3:


The cost-based optimiser goes through a few stages, including query transformation. Your query has almost certainly be rewritten by the optimiser to:

select countries.* from countries join regions on (countries.region_id = regions.region_id) where regions.region_name = 'Europe';

So the concept of inner and outer queries as represented in the original query may not apply post-transformation. Incidentally, this is why arguments concerning EXISTS () vs IN () are often moot -- the query in both cases can often be rewritten as a join.

Among the information that the optimiser uses (version dependent) are:

  1. Statistics on the table
  2. Statistics on the table columns
  3. Histograms of table column values
  4. Presence of indexes
  5. Size and type of, and statistics on, indexes -- in particular the clustering factor
  6. Presence of constraints -- including not null and check constraints.
  7. Estimated cost of single and multiblock reads and cpu ops per second.
  8. Partitioning
  9. Presence and state of materialised views and/or query rewrite declarations.
  10. Performance of previous versions of the query.

So in short, don't be surprised by anything the optimiser does. It's a very sophisticated piece of kit.



来源:https://stackoverflow.com/questions/15576158/understanding-explain-plan-in-oracle

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!