Показаны сообщения с ярлыком Tuning. Показать все сообщения
Показаны сообщения с ярлыком Tuning. Показать все сообщения

2 апреля 2009 г.

Invalidating the execution plan of an SQL statement

Recently, I noticed that although I gathered statistics on a table, the execution plan wasn't invalidated in Oracle 10g. I googled it and found the solution at Coskan's blog that you can invalidate an execution plan by executing a simple ddl statement on a table, like:

grant select on t1 to user1;

Today I came across this note on metalink [Doc ID: 557661.1] about this topic. It says that prior to 10g, by default the execution plan was invalidated when the statistics was gathered on underlying objects:
Cursor Invalidations on Gathering Statistics prior to Oracle10g
In releases prior to Oracle10g gathering statistics using DBMS_STATS resulted in immediate invalidations of dependent cached cursors, unless NO_INVALIDATE was set to TRUE.

But starting with 10g, by default statistics gathering MAY OR MAY NOT invalidate the execution plan:
Starting with Oracle10g, the DBMS_STATS package offers the AUTO_INVALIDATE option for the NO_INVALIDATE parameter of its GATHER_xxx_STATS and DELETE_xxx_STATS procedures. This parameter allows the user to specify when to invalidate dependent cursors i.e. cursors cached in the library cache area of the shared pool which reference a table, index, column or fixed object whose statistics are modified by the procedure call.
According to the documentation the values NO_INVALIDATE can take are:

TRUE: does not invalidate the dependent cursors
FALSE: invalidates the dependent cursors immediately
AUTO_INVALIDATE (default): have Oracle decide when to invalidate dependent cursors

So if you want to be sure that the cursor is invalidated after statistics gathering, use parameter NO_INVALIDATE => FALSE with DBMS_STATS.GATHER_TABLE_STATS and other procedures.
exec dbms_stats.gather_table_stats('USER','EMP', no_invalidate => false);
As for the default AUTO_INVALIDATE option , when Oracle decides him/herself whether to invalidate or not invalidate an execution plan, they give a description of how it works. To be frank, I didn't read it all now, maybe I will read it when I need this info next time. So here is the exceprt from [Doc ID: 557661.1]:
Cursor Invalidations with Oracle10g and AUTO_INVALIDATE
With the AUTO_INVALIDATE option the goal is to spread out the cursor invalidations over a time period long enough for hard-parses not to cause noticeable spikes.

In this way a cached cursor depending on an object whose statistics have been modified by DBMS_STATS will be invalidated as follows:

when DBMS_STATS modifies statistics for an object, all current cached cursors depending on this object are marked for rolling invalidation. Let's call this time T0.

the next time a session parses a cursor marked for rolling invalidation, it sets a timestamp. This timestamp can take a random value up to _optimizer_invalidation_period sec from the time of this parse. The default for this parameter is 18000 sec i.e. 5 hours. Let's call the time of this parse T1 and the timestamp value Tmax. On this (first) parse we reuse the existing cursor i.e. we do not hard-parse and do not use the modified statistics to generate a new plan (it is a soft parse.)

on every subsequent parse of this cursor (which is now marked for rolling invalidation and timestamped) we check whether the current time T2 exceeds the timestamp Tmax. If not, we reuse the existing cursor again, as happened on the first (soft) parse at time T1. If Tmax has been exceeded, we invalidate the cached cursor and create a new version of it (a new child cursor) which uses the new statistics of the object to generate its execution plan. The new child is marked ROLL_INVALID_MISMATCH in V$SQL_SHARED_CURSOR to explain why we could not share the previous child.
From the above descriptions, it follows that:

a cursor which is never parsed again after being marked for rolling invalidation will not be invalidated and may eventually be flushed out of the shared pool if memory becomes scarce
a cursor which is only parsed once after being marked for rolling invalidation will not be invalidated (it will only be timestamped) and again may be eventually flushed out if memory in the shared pool becomes scarce
cursors which are regularly reused will become invalidated on the next parse that happens after the timestamp Tmax has been exceeded
It should be clear that the above method is efficient in that it incurs the overhead of invalidations only for frequently reused cursors.

Exception: parallel SQL are immediately invalidated in order to ensure consistency between execution plans of slaves and Query Coordinator across multiple RAC instances. This is not a problem as parallel SQL are usually heavy and therefore hard-parse resources are insignificant to their total resource usage.

14 мая 2008 г.

Где именно находится оптимизатор
в архитектуре Oracle RDBMS?

Oracle DBA обычно не интересуются вопросом "Где именно находится оптимизатор в архитектуре Oracle RDBMS?" Некоторые из моих знакомые ДБА отнесли его к категории вопросов о смысле жизни.
Но самый популярный ответ был "в ядре Oracle".

В книге Oracle Database 10g Insider Solutions пишут тоже самое:

"The Cost Based Optimizer is at the heart of the Oracle kernel and plays a large part in the efficient execution of SQL statements in Oracle Database 10g."
Но где именно находится это ядро (kernel)? Это обычный процесс? Если да, то можно ли его увидеть в юниксе в списке процессов командой "ps"?

Отрывок из книги Тома Кайта "Oracle для профессионалов: Архитектура и основные особенности":
"При получении запроса SELECT * FROM EMP именно выделенный/разделяемый сервер Oracle будет разбирать его и помещать в разделяемый пул (или находить соответствующий запрос в разделяемом пуле). Именно этот процесс создает план выполнения запроса. Этот процесс реализует план запроса, находя необходимые данные в буферном кеше или считывая данные в буферный кеш с диска. Такие серверные процессы можно назвать "рабочими лашадками" СУБД. Часто именно они потребляют основную часть процессорного времени в системе, поскольку выполняют сортировку, суммирование, соединения - в общем, почти все."
То есть функции оптимизатора выполняются серверными процессами и их мы можем увидеть в списке процессов:
oracle@myhost$ ps -ef  grep ora  grep LOCAL  more
oracle 22790 1 0 09:13:33 ? 0:03 oracleTESTDB (LOCAL=NO)
oracle 4426 1 0 11:20:58 ? 0:02 oracleTESTDB (LOCAL=NO)
oracle 29167 1 0 11:11:32 ? 0:01 oracleTESTDB (LOCAL=NO)
oracle 12778 1 0 09:53:02 ? 0:03 oracleTESTDB (LOCAL=NO)
oracle 14349 1 0 12:26:34 ? 0:01 oracleTESTDB (LOCAL=NO)
oracle 21141 1 0 11:47:35 ? 0:01 oracleTESTDB (LOCAL=NO)
oracle 11220 1 0 09:49:18 ? 0:06 oracleTESTDB (LOCAL=NO)
oracle 16823 1 0 11:40:49 ? 0:01 oracleTESTDB (LOCAL=NO)
oracle 26760 1 0 11:57:20 ? 0:01 oracleTESTDB (LOCAL=NO)
oracle 20814 1 0 09:09:42 ? 0:01 oracleTESTDB (LOCAL=NO)
oracle 17374 1 0 12:32:28 ? 0:02 oracleTESTDB (LOCAL=NO)
oracle 8911 1 0 22:14:38 ? 0:00 oracleTESTDB (LOCAL=NO)
Если серверные процессы разбирают все запросы (выполняют все функции оптимизатора), значит ли это, что:

Код самого оптимизатора находится в каждом серверном процессе?
Или серверные процессы всего лишь вызывают эти функции из ярда Oracle?
Или ядро Oracle - это и есть серверные процессы?


Для меня этот вопрос все еще остается открытым, если у кого-то есть идеи, буду рада их услышать.

Добавлено 16 мая, 2008:
Это ответ Джонатана Льюиса на этот вопрос (публикую с его разрешения):
There is one main executable for the database in Oracle distribution, and that is called oracle (on Unix systems, but oracle.exe on Windows).
This is the program that becomes pmon, smon, dbwr, s000, and all the other background processes when the instance starts up. The bits of code run from that executable vary across the different roles played in the instance.

As such, the optimiser is just part of the code that is called only by a program which is taking on the role of a dedicated server (oracle_{SID}_nnn in unix variants) or a shared server (oracle_{SID}_Snnn).

When people talk about the 'Oracle kernel' it's actually a very informal and inaccurate expression - they are trying to give a vague impression of the most commonly used part of the code with an emphasis, perhaps, on the code segments that do a lot of synchronised work in the shared memory area. But there is no specific process that you can see that is "the" kernel.

Regards

Jonathan Lewis
http://jonathanlewis.wordpress.com

Author: Cost Based Oracle: Fundamentals
http://www.jlcomp.demon.co.uk/cbo_book/ind_book.html

The Co-operative Oracle Users' FAQ
http://www.jlcomp.demon.co.uk/faq/ind_faq.html
Перевод:

Есть один основной бинарник в дистрибутиве Oracle, который так и называется oracle (в юникс системах, и oracle.exe в Windows). Когда стартуется инстанс, эта программа превращается в фоновые процессы pmon, smon, dbwr, s000 и тд.
В зависимости от роли, которую он выполняет в составе инстанса, выполняются отдельные биты кода этого бинарника.

Оптимизатор - это всего лишь кусочек кода, который вызывается программой, выполняющей роль выделенного сервера (oracle_{SID}_nnn в юниксе) или разделяемого сервера (oracle_{SID}_Snnn).

Когда люди говорят о "ядре Oracle", они на самом деле используют неформальное и не совсем точное выражение - они стараются дать смутное ощущение о часто используемой части кода, возможно имея ввиду сегменты кода, которые выполняют кучу синхронизированных операций в разделяемой памяти.
Но на самом деле нет отдельного процесса, которого можно увидеть и который являлся бы "ядром".

Прикольно, значит код самого оптимизатора находится в каждом серверном процессе.
Спасибо всем, кто участвовал в процессе выяснения местонахождения оптимизатора в архитектуре Oracle. Отдельное спасибо Джонатану Льюису, кстати всем, кто занимается тюнингом, рекомендую почитать его книжку Основы Стоимостной Оптимизации (Cost-Based Oracle Fundamentals).