<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4791872513565348125</id><updated>2024-11-06T05:04:44.490+02:00</updated><category term="oracle"/><category term="pl/sql"/><category term="oracle 11.2"/><category term="plsqlchallenge"/><category term="задачка"/><category term="11.2"/><category term="11g"/><category term="collection"/><category term="index range scan"/><category term="java stored"/><category term="optimization"/><category term="oracle undocumented behaviour"/><category term="parallel"/><category term="partitioning"/><category term="regexp"/><category term="regexp replace substring"/><category term="result_cache"/><category term="select for update of"/><category term="subquery factoring"/><category term="диапазон"/><category term="типы"/><category term="11.1"/><category term="Get_cardinality"/><category term="ORACLE XT_REGEXP"/><category term="PL/SQL developer"/><category term="PL/Scope"/><category term="Top N"/><category term="autonomous_transaction"/><category term="binary_float_infinity"/><category term="binary_float_nan"/><category term="buffer sort"/><category term="bug"/><category term="bug ssc"/><category term="cardinality"/><category term="challenge"/><category term="clob"/><category term="codegolf"/><category term="collect"/><category term="compare"/><category term="constraints"/><category term="create constraint in parallel"/><category term="dbms_random"/><category term="deterministic functions"/><category term="diagnostics events"/><category term="distinct values"/><category term="dml allocation latch"/><category term="docs.oracle.com"/><category term="enum"/><category term="exception"/><category term="execute operating system commands with timeout"/><category term="foreign key"/><category term="git"/><category term="global temporary table"/><category term="golf"/><category term="gv$lock"/><category term="hint"/><category term="hints"/><category term="indexes"/><category term="infinity"/><category term="invalidation"/><category term="iterator"/><category term="join string"/><category term="latch free"/><category term="latches"/><category term="look-around assertion"/><category term="materialization"/><category term="materialize"/><category term="member of"/><category term="mercurial"/><category term="model"/><category term="mysql"/><category term="nan"/><category term="no_data_found"/><category term="ora-01762"/><category term="ora-32035"/><category term="ora-600"/><category term="oracle spatial function based indexes"/><category term="oracle sql"/><category term="parallel execution"/><category term="parallel_enable"/><category term="parallel_index"/><category term="partition range iterator descending"/><category term="perl"/><category term="plan_table"/><category term="predefined типы"/><category term="quiz"/><category term="ranges"/><category term="recursive sessions"/><category term="runstats package"/><category term="session_user"/><category term="split string"/><category term="sprintf"/><category term="sql"/><category term="subversion"/><category term="svn"/><category term="sys.anydata"/><category term="sys_context"/><category term="sys_refcursor"/><category term="trace 10032"/><category term="trace 10046"/><category term="trace events"/><category term="trace levels"/><category term="translation"/><category term="undocumented hints"/><category term="unwrap"/><category term="user"/><category term="v$lock"/><category term="with"/><category term="wrap"/><category term="в случае одной таблицы"/><category term="документация oracle"/><category term="коллекции"/><category term="массив"/><category term="миниоткат"/><category term="недокументированные"/><category term="одна строка"/><category term="одно условие"/><category term="оптимизация"/><category term="перевод"/><category term="прочее"/><category term="рестарт"/><category term="секционирование"/><category term="типы-перечисления"/><category term="хинты"/><title type='text'>XT&amp;amp;R blackboard</title><subtitle type='html'>Just another Oracle developer&#xa;Саян Малакшинов</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.xt-r.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default?start-index=26&amp;max-results=25'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>63</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-771492544261815557</id><published>2014-01-15T01:02:00.001+03:00</published><updated>2015-04-30T21:15:39.111+02:00</updated><title type='text'>Все, что за 2013-й год накопилось неопубликованного</title><content type='html'>Все не хватает времени закросспостить, поэтому просто проведу инвентаризацию :) &lt;br /&gt;
Список ссылок на неопубликованное из моего второго блога с короткими пояснениями:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Все о кешировании deterministic функций: &lt;a href=&quot;http://orasql.org/category/oracle/deterministic-functions/&quot;&gt;http://orasql.org/category/oracle/deterministic-functions/&lt;/a&gt;&lt;br /&gt;
В этом цикле я рассказываю о том, как устроен механизм их кеширования и сравниваю с механизмом кеширования скалярных подзапросов, а также немного о том, как оптимизируются циклы в PL/SQL.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Пример контроля &quot;direct path reads&quot; при фул сканах с помощью хинтов или профилей с INDEX_STATS/TABLE_STATS: &lt;a href=&quot;http://orasql.org/category/oracle/adaptive-serial-direct-path-reads/&quot;&gt;adaptive serial direct path reads&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Про нежелательный inlist iterator по составным индексам: &lt;a href=&quot;http://orasql.org/tag/inlist-iterator/&quot;&gt;http://orasql.org/tag/inlist-iterator/&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Различные трюки для SQL*Plus: &lt;a href=&quot;http://orasql.org/category/oracle/sqlplus/&quot;&gt;http://orasql.org/category/oracle/sqlplus/&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Просто парочка общеизвестных ошибок, но часто пропускаемых по невнимательности: &lt;a href=&quot;http://orasql.org/2013/05/28/a-couple-of-well-known-and-often-forgotten-things-for-plsql-developers/&quot;&gt;a-couple-of-well-known-and-often-forgotten-things-for-plsql-developers&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Как избавиться от многократного вызова функции из-за протолкнутых предикатов не изменяя кода: &lt;a href=&quot;http://orasql.org/2013/06/10/too-many-function-executions/&quot;&gt;http://orasql.org/2013/06/10/too-many-function-executions/&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Всякая всячина о внутренностях 12с: inline функции, наконец-то разрешенный lateral, extended varchars, identities и defaults: &lt;a href=&quot;http://orasql.org/category/oracle/12c/&quot;&gt;http://orasql.org/category/oracle/12c/&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Трюк с переопределением объекта используемого в &quot;чужой&quot; вьюхе, на примере получения списка всех таблиц непривилигированным пользователем: http://orasql.org/2014/01/14/a-little-trick-with-redefining-any-object-in-a-view-from-another-schema/&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Ну и напоследок &lt;a href=&quot;http://orasql.org/scripts/get_binds_from_trace_by_sqlid.pl&quot;&gt;минискриптик-набросочек&lt;/a&gt; для получения биндов из файла трассировки по заданному sql_id в xml или json, который мало кому-нибудь будет нужен, но мне пришлось наваять вчера :)&lt;br /&gt;
&lt;br /&gt;
зы. Надеюсь, я когда-нибудь все это оформлю нормально...</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/771492544261815557/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2014/01/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/771492544261815557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/771492544261815557'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2014/01/blog-post.html' title='Все, что за 2013-й год накопилось неопубликованного'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-1571728836756579807</id><published>2013-05-15T00:36:00.000+03:00</published><updated>2013-05-15T00:36:41.065+03:00</updated><title type='text'>Пара простых примеров по вчерашней дискуссии после семинара</title><content type='html'>1. Пример, показывающий короткие clob&#39;ы с &quot;enable storage in row&quot; будут передаваться точно так же как и обычные:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SQL&gt; create table xt_clob(c clob) lob(c) store as securefile(enable storage in row);

Table created.

SQL&gt; insert into xt_clob select lpad(&#39;x&#39;,100) from dual connect by level&lt;=10;

10 rows created.

SQL&gt; commit;

Commit complete.

SQL&gt; set autot trace stat
SQL&gt; select * from xt_clob;

10 rows selected.


Statistics
----------------------------------------------------------
          5  recursive calls
          0  db block gets
         24  consistent gets
          5  physical reads
          0  redo size
       6748  bytes sent via SQL*Net to client
       8585  bytes received via SQL*Net from client
         12  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         10  rows processed
&lt;/pre&gt;2. Пример, показывающий что строчный before триггер без всяких дополнительный манипуляций прекрасно увеличивает current&#39;ы:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SQL&gt; drop table xt_curr purge;

Table dropped.

SQL&gt; create table xt_curr as select level a,level b from dual connect by level&lt;=1e4;

Table created.

SQL&gt; set autot trace stat;
SQL&gt; update xt_curr set b=a;

10000 rows updated.


Statistics
----------------------------------------------------------
         50  recursive calls
        130  db block gets
         52  consistent gets
         36  physical reads
     872008  redo size
        684  bytes sent via SQL*Net to client
        590  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
      10000  rows processed

SQL&gt; roll;
Rollback complete.
SQL&gt; set autot off;
SQL&gt; create or replace trigger tr_xt_curr before update on xt_curr for each row
  2  begin
  3    if :new.a !=:old.a and :new.b != :old.b then
  4      :new.b := :new.b/(:old.b - :new.b);
  5    end if;
  6  end;
  7  /

Trigger created.

SQL&gt; set autot trace stat;
SQL&gt; update xt_curr set b=a;

10000 rows updated.


Statistics
----------------------------------------------------------
          8  recursive calls
      20376  db block gets
         54  consistent gets
         18  physical reads
    4411636  redo size
        684  bytes sent via SQL*Net to client
        590  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
      10000  rows processed

SQL&gt; roll;
Rollback complete.
SQL&gt; set autot off echo off;
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/1571728836756579807/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2013/05/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/1571728836756579807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/1571728836756579807'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2013/05/blog-post.html' title='Пара простых примеров по вчерашней дискуссии после семинара'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-8410573133124552761</id><published>2013-02-10T23:57:00.000+03:00</published><updated>2013-02-10T23:57:58.358+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="deterministic functions"/><category scheme="http://www.blogger.com/atom/ns#" term="materialization"/><category scheme="http://www.blogger.com/atom/ns#" term="materialize"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="runstats package"/><category scheme="http://www.blogger.com/atom/ns#" term="subquery factoring"/><title type='text'>Новые посты на orasql.org</title><content type='html'>К сожалению, опять пока не успел сделать версию на русском поэтому пока просто ссылки с кратким описанием:&lt;br /&gt;
1. &lt;a href=&quot;http://orasql.org/2013/02/10/deterministic-function-vs-scalar-subquery-caching-part-1/&quot;&gt;Сравнение механизмов кэширования deterministic функций и scalar subquery caching&lt;/a&gt;&lt;br /&gt;
2. &lt;a href=&quot;http://orasql.org/2013/02/09/materialization-in-subquery-factoring-without-hint-materialize-can-be-considered-only-when-exists-at-least-one-predicate/&quot;&gt;Краткий пример того, что материализация subquery factoring может быть рассмотрена CBO(без хинта) только если есть хоть один предикат, даже бессмысленный 1=1&lt;/a&gt;&lt;br /&gt;
3. &lt;a href=&quot;http://orasql.org/2013/01/21/just-another-version-of-tom-kytes-runstats-runstats_pkg/&quot;&gt;Моя версия Кайтовского runstats&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/8410573133124552761/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2013/02/orasqlorg.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/8410573133124552761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/8410573133124552761'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2013/02/orasqlorg.html' title='Новые посты на orasql.org'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-1838635414698140493</id><published>2012-10-31T02:11:00.000+03:00</published><updated>2012-10-31T02:15:51.509+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="11.2"/><category scheme="http://www.blogger.com/atom/ns#" term="diagnostics events"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle undocumented behaviour"/><category scheme="http://www.blogger.com/atom/ns#" term="trace 10032"/><category scheme="http://www.blogger.com/atom/ns#" term="trace events"/><title type='text'>“Abridged” call stack в трассировке &quot;dump sort statistics&quot;(event 10032)</title><content type='html'>Пару месяцев назад я обнаружил, что в трассировке сортировки в &lt;b&gt;11.2.0.3&lt;/b&gt; появился &lt;b&gt;short call stack&lt;/b&gt; и даже уже советовал на форуме как более простой &lt;b&gt;oradebug short_stack&lt;/b&gt;, хотя, честно говоря, из-за тотального недостатка свободного времени до сих пор не разбирался в отличиях. Я даже не знаю с 11.2.0.2 или 11.2.0.3 он появился, т.к. все время забываю это проверить, когда есть под рукой 11.2.0.2, но в 11.2.0.1 его точно не было.&lt;br /&gt;
&lt;br /&gt;
Под катом пример:&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Включаем трассировку с 10-м уровнем:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;alter session set events &#39;10032 trace name context forever, level 10&#39;;
&lt;/pre&gt;Кусок из трейс файла:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;soropn: opened (new) sort, sordef 0x7fc4679e2550, flags 0x802
        maxkey 25, nflds 12, nkflds 1

*** 2012-10-30 23:14:34.678
----- Current SQL Statement for this session (sql_id=3ktacv9r56b51) -----
select owner#,name,namespace,remoteowner,linkname,p_timestamp,p_obj#, nvl(property,0),subname,type#,d_attrs from dependency$ d, obj$ o where d_obj#=:1 and p_obj#=obj#(+) order by order#
        Abridged call stack trace:
ksedsts&lt;-soropn&lt;-qersoProcessULS&lt;-qersoFetch&lt;-opifch2&lt;-opifch&lt;-opiodr&lt;-rpidrus&lt;-skgmstack&lt;-rpiswu2&lt;-rpidrv&lt;-rpifch&lt;-kqllod&lt;-kglobld&lt;-kglobpn&lt;-kglpim&lt;-kglpin&lt;-kglgob&lt;-kgldpo0&lt;-qcdlgpo&lt;-qcsRslvPLSQLInvoc1&lt;-qcsRslvPLSQLInvoc&lt;-qcsRslvName&lt;-qcsridn&lt;-qcsraic&lt;-qcspqbDescendents
&lt;-qcspqb&lt;-kkmdrv&lt;-opiSem&lt;-opiDeferredSem&lt;-opitca&lt;-kksFullTypeCheck&lt;-rpiswu2&lt;-kksLoadChild&lt;-kxsGetRuntimeLock&lt;-kksfbc&lt;-kkspsc0&lt;-kksParseCursor&lt;-opiosq0&lt;-kpooprx&lt;-kpoal8&lt;-opiodr&lt;-ttcpip&lt;-opitsk&lt;-opiino&lt;-opiodr&lt;-opidrv&lt;-sou2o&lt;-opimai_real&lt;-ssthrdmain&lt;-main&lt;-__libc_start_main
&lt;-_start        End of abridged call stack trace.

*** 2012-10-30 23:14:35.328
soreod: sorp 0x7fc4679e2550
---- Sort Parameters ------------------------------
sort_area_size                    65536
sort_area_retained_size           65536
sort_multiblock_read_count        1
max intermediate merge width      3

&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/1838635414698140493/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/10/abridged-call-stack-dump-sort.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/1838635414698140493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/1838635414698140493'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/10/abridged-call-stack-dump-sort.html' title='“Abridged” call stack в трассировке &quot;dump sort statistics&quot;(event 10032)'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-2094116721018912284</id><published>2012-10-15T21:04:00.001+03:00</published><updated>2012-10-15T21:04:25.637+03:00</updated><title type='text'>Английская версия блога - orasql.org</title><content type='html'>Я недавно открыл версию своего блога на английском и кое-что оттуда не успел запостить сюда, поэтому исправляюсь и вкратце резюмирую свои два поста:&lt;br /&gt;
&lt;br /&gt;
1. &lt;a href=&quot;http://orasql.org/2012/10/12/easy-way-to-tracing/&quot;&gt;Удобная трассировка&lt;/a&gt;:&lt;br /&gt;
Очень удобно создать отдельный сервис и включить на нем трассировку: теперь чтобы оттрассировать приложение или обращения с дблинка достаточно подключиться к на нужный сервис. Код доступен по ссылке&lt;br /&gt;
&lt;br /&gt;
2. &lt;a href=&quot;http://orasql.org/2012/10/13/deceptive-commit-after-select-from-dblink/&quot;&gt;Rollback вместо commit&#39;a на дблинке&lt;/a&gt;: &lt;br /&gt;
При коммите после select * from tab@dblink на самом деле коммит будет только на локальном инстансе, а на самом дблинке будет роллбэк. При этом они оба будут &quot;read-only&quot;. Кроме того, если после коммита/роллбэка мы будем еще вызывать коммиты/роллбэки на ремоут не будет ни коммита, ни роллбэка, однако, при отключении от локального инстансе(то есть просто при дисконнекте) на ремоут придет read-only commit. А как увидеть и каким же образом определяется, что будет коммит или роллбэк на ремоуте, непонятно...</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/2094116721018912284/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/10/orasqlorg.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/2094116721018912284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/2094116721018912284'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/10/orasqlorg.html' title='Английская версия блога - orasql.org'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-500909580743469682</id><published>2012-09-21T01:58:00.000+03:00</published><updated>2012-09-22T03:29:14.307+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="distinct values"/><category scheme="http://www.blogger.com/atom/ns#" term="optimization"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle 11.2"/><category scheme="http://www.blogger.com/atom/ns#" term="Top N"/><category scheme="http://www.blogger.com/atom/ns#" term="оптимизация"/><title type='text'>Удивительная оптимизация получения distinct values из индекса, а также TopN для каждого</title><content type='html'>Несколько дней назад на форуме задали, как изначально показалось, старый, скучный, вдоль и поперек изъезженный &lt;a href=&quot;http://www.sql.ru/forum/actualthread.aspx?tid=969857&quot;&gt;вопрос&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;Есть лента новостей. Все новости разделены на 10 категорий(Политика, спорт, авто, недвижимость и тд).&lt;br /&gt;
Надо 1 запросом для каждой категории выбрать 4 новости.&lt;br /&gt;
Получается если перебрать результат - сразу идет 4 новости о политике, затем 4 новости о спорте и тд.&lt;/blockquote&gt;Однако, задача стояла - сделать это оптимально, а стандартное решение с обычным TopN через row_number никак оптимальным не назвать, особенно в случае больших таблиц, относительно небольшого количества категорий и неравномерного распределения или просто общей низкой селективности. И вот после нескольких более-менее хороших вариантов, подглядев в решение с PostgreSQL(правда я в нем не стал сильно разбираться, достаточно было увидеть рекурсию, min и предикат), получился отличный вариант.&lt;br /&gt;
&lt;br /&gt;
Но обо всем по порядку:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;1. Получение distinct значений из индекса&lt;/b&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
Пусть есть табличка с индексом на поле а:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;create table xt_test(a not null,b not null,c)
as
select 
    length(object_name)
   ,nvl(object_id,0)
   ,o.OBJECT_NAME 
from dba_objects o;
create index ix_test_a on xt_test(a);
DB11G/XTENDER&gt; select i.index_name
  2        ,i.distinct_keys,i.num_rows
  3        ,i.blevel,i.leaf_blocks
  4        ,i.avg_leaf_blocks_per_key,i.avg_data_blocks_per_key
  5  from user_indexes i where i.table_name=&#39;XT_TEST&#39;;

INDEX_NAME  DISTINCT_KEYS  NUM_ROWS   BLEVEL LEAF_BLOCKS AVG_LEAF_BLOCKS_PER_KEY AVG_DATA_BLOCKS_PER_KEY
----------- ------------- --------- -------- ----------- ----------------------- -----------------------
IX_TEST_A              30     69230        1         135                       4                     191

1 row selected.
&lt;/pre&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Весь код создания таблицы&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;drop table xt_test purge;
create table xt_test(a not null,b not null,c)
as
select 
    length(object_name)
   ,nvl(object_id,0)
   ,o.OBJECT_NAME 
from dba_objects o 
;
create index ix_test_a on xt_test(a);
begin
  dbms_stats.gather_table_stats( &#39;&#39;
                                ,&#39;XT_TEST&#39;
                                ,estimate_percent=&gt;100
                                ,cascade=&gt;true
                                ,method_opt =&gt; &#39;for all indexed columns size auto&#39;
                               ); 
end;
/

select i.index_name
      ,i.distinct_keys,i.num_rows
      ,i.blevel,i.leaf_blocks
      ,i.avg_leaf_blocks_per_key,i.avg_data_blocks_per_key 
from user_indexes i where i.table_name=&#39;XT_TEST&#39;;
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
Распределение значений у этого поля очень неравномерное:&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Распределение&quot;&gt;&lt;table BORDER=&quot;1&quot;&gt;&lt;tr&gt;&lt;th&gt;A&lt;/TH&gt;&lt;th&gt;COUNT(*)&lt;/TH&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/TD&gt;&lt;td&gt;11&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/TD&gt;&lt;td&gt;20&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/TD&gt;&lt;td&gt;59&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/TD&gt;&lt;td&gt;92&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/TD&gt;&lt;td&gt;178&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;6&lt;/TD&gt;&lt;td&gt;251&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;7&lt;/TD&gt;&lt;td&gt;521&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;9&lt;/TD&gt;&lt;td&gt;570&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;10&lt;/TD&gt;&lt;td&gt;636&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;8&lt;/TD&gt;&lt;td&gt;640&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;11&lt;/TD&gt;&lt;td&gt;962&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;12&lt;/TD&gt;&lt;td&gt;970&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;13&lt;/TD&gt;&lt;td&gt;1151&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;15&lt;/TD&gt;&lt;td&gt;1363&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;14&lt;/TD&gt;&lt;td&gt;1544&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;16&lt;/TD&gt;&lt;td&gt;1692&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;18&lt;/TD&gt;&lt;td&gt;2021&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;17&lt;/TD&gt;&lt;td&gt;2023&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;19&lt;/TD&gt;&lt;td&gt;2550&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;20&lt;/TD&gt;&lt;td&gt;2606&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;21&lt;/TD&gt;&lt;td&gt;3050&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;22&lt;/TD&gt;&lt;td&gt;3171&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;23&lt;/TD&gt;&lt;td&gt;3395&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;24&lt;/TD&gt;&lt;td&gt;3472&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;29&lt;/TD&gt;&lt;td&gt;3527&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;27&lt;/TD&gt;&lt;td&gt;3596&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;26&lt;/TD&gt;&lt;td&gt;3698&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;28&lt;/TD&gt;&lt;td&gt;4130&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;25&lt;/TD&gt;&lt;td&gt;4268&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;30&lt;/TD&gt;&lt;td&gt;17063&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;Всего&lt;/TD&gt;&lt;td&gt;69230&lt;/TD&gt;&lt;/TR&gt;
&lt;/TABLE&gt;&lt;/div&gt;Стандартный запрос c distinct очень неудачен - в индексе всего 30 distinct_keys, а прочитать придется 135 блоков!&lt;br /&gt;
С IFS:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; select/*+ INDEX(xt_test) */ distinct a from xt_test;

30 rows selected.

Elapsed: 00:00:00.02

Execution Plan
----------------------------------------------------------
Plan hash value: 3405466263

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |    30 |    90 |   140   (3)| 00:00:02 |
|   1 |  SORT UNIQUE NOSORT|           |    30 |    90 |   140   (3)| 00:00:02 |
|   2 |   INDEX FULL SCAN  | IX_TEST_A | 69230 |   202K|   137   (1)| 00:00:02 |
--------------------------------------------------------------------------------


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        138  consistent gets
          0  physical reads
          0  redo size
        751  bytes sent via SQL*Net to client
        431  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         30  rows processed
&lt;/pre&gt;C IFFS:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; select distinct a from xt_test;

30 rows selected.

Elapsed: 00:00:00.05

Execution Plan
----------------------------------------------------------
Plan hash value: 4206828362

-----------------------------------------------------------------------------------
| Id  | Operation             | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |           |    30 |    90 |    42  (10)| 00:00:01 |
|   1 |  HASH UNIQUE          |           |    30 |    90 |    42  (10)| 00:00:01 |
|   2 |   INDEX FAST FULL SCAN| IX_TEST_A | 69230 |   202K|    38   (0)| 00:00:01 |
-----------------------------------------------------------------------------------


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        143  consistent gets
          0  physical reads
          0  redo size
        751  bytes sent via SQL*Net to client
        431  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         30  rows processed
&lt;/pre&gt;А ведь можно же было бы идти по дереву заходя только в нужные блоки, а не по всем листовым блокам! Однако, Oracle сам по себе такое не осилит и тут как раз придется его выкрутиться: у Oracle помимо IFS(min/max) есть и IRS(min/max) хорошо работающий с диапазонами и границами, и с помощью рекурсивного запроса, можно заставить его читать только нужное!&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; with t_unique( a ) as (
  2                select min(t1.a)
  3                from xt_test t1
  4                union all
  5                select (select min(t1.a) from xt_test t1 where t1.a&gt;t.a)
  6                from t_unique t
  7                where a is not null
  8  )
  9  select * from t_unique where a is not null;

30 rows selected.

Elapsed: 00:00:00.00

Execution Plan
----------------------------------------------------------
Plan hash value: 2791305641

-------------------------------------------------------------------------------------------------------
| Id  | Operation                                 | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                          |           |     2 |    26 |     4   (0)| 00:00:01 |
|*  1 |  VIEW                                     |           |     2 |    26 |     4   (0)| 00:00:01 |
|   2 |   UNION ALL (RECURSIVE WITH) BREADTH FIRST|           |       |       |            |          |
|   3 |    SORT AGGREGATE                         |           |     1 |     3 |            |          |
|   4 |     INDEX FULL SCAN (MIN/MAX)             | IX_TEST_A |     1 |     3 |     2   (0)| 00:00:01 |
|   5 |    SORT AGGREGATE                         |           |     1 |     3 |            |          |
|   6 |     FIRST ROW                             |           |     1 |     3 |     2   (0)| 00:00:01 |
|*  7 |      INDEX RANGE SCAN (MIN/MAX)           | IX_TEST_A |     1 |     3 |     2   (0)| 00:00:01 |
|*  8 |    RECURSIVE WITH PUMP                    |           |       |       |            |          |
-------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(&quot;A&quot; IS NOT NULL)
   7 - access(&quot;T1&quot;.&quot;A&quot;&gt;:B1)
   8 - filter(&quot;A&quot; IS NOT NULL)


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
         36  consistent gets
          0  physical reads
          0  redo size
        751  bytes sent via SQL*Net to client
        431  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
         32  sorts (memory)
          0  sorts (disk)
         30  rows processed
&lt;/pre&gt;Разница очевидна: 36 consistent gets на 30 значений, вместо 135. И это очень маленькая табличка, а на миллионах и миллиардах записей разница будет еще более огромной!&lt;br /&gt;
Поясню алгоритм: &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;В первой части union all (3-4 строки плана) мы указываем с чего начать рекурсию, а конкретно выбираем минимальное(первое) значение из индекса.&lt;/li&gt;
&lt;li&gt;Затем с помощью IRS(min/max) (7-6-5 строки плана) выбираем первое значение большее выбранного на предыдущем этапе&lt;/li&gt;
&lt;li&gt;Повторяем рекурсию пока что-то находим&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Переходим к следующему:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;2. Топ N записей для каждого значению ключа&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Теперь вооруженные легким получением каждого начального значения, мы легко можем получить Топ для каждого из них, но для этого придется воспользоваться либо недокументированным Lateral() с включением соответствующего ивента, либо более простым и стандартным table(). Проблема остается только в том, что воспользоваться инлайн вью с row_number/rownum не получится, т.к. предикат с верхнего уровня не просунется, и придется воспользоваться простым ограничением по count stop key(по rownum) c обязательным доступом по IRS descending (order by там в общем лишний, но дополнительно уменьшает стоимость чтения IRS descending который нам и нужен для неявной сортировки) c подсказкой index_desc, чтобы прибить намертво, иначе сортировка может слететь:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; with t_unique( a ) as (
  2                select min(t1.a)
  3                from xt_test t1
  4                union all
  5                select (select min(t1.a) from xt_test t1 where t1.a&gt;t.a)
  6                from t_unique t
  7                where a is not null
  8  )
  9  select/*+ use_nl(rids tt) */ *
 10  from t_unique v
 11      ,table(
 12            cast(
 13                 multiset(
 14                          select/*+ index_desc(tt ix_xt_test_ab) */ tt.rowid rid
 15                          from xt_test tt
 16                          where tt.a=v.a
 17                            and rownum&lt;=5
 18                          order by tt.b desc
 19                         )
 20                 as sys.odcivarchar2list
 21                )
 22            ) rids
 23      ,xt_test tt
 24  where tt.rowid=rids.column_value
 25  order by tt.a,tt.b desc;

150 rows selected.

Elapsed: 00:00:00.01

Execution Plan
----------------------------------------------------------
Plan hash value: 4085270117

----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                    | Name          | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                             |               |    11M|   506M|       |   149K  (1)| 00:29:54 |
|   1 |  SORT ORDER BY                               |               |    11M|   506M|   649M|   149K  (1)| 00:29:54 |
|   2 |   NESTED LOOPS                               |               |    11M|   506M|       | 16402   (1)| 00:03:17 |
|   3 |    NESTED LOOPS                              |               | 16336 |   239K|       |    60   (0)| 00:00:01 |
|   4 |     VIEW                                     |               |     2 |    26 |       |     4   (0)| 00:00:01 |
|   5 |      UNION ALL (RECURSIVE WITH) BREADTH FIRST|               |       |       |       |         |             |
|   6 |       SORT AGGREGATE                         |               |     1 |     3 |       |         |             |
|   7 |        INDEX FULL SCAN (MIN/MAX)             | IX_TEST_A     |     1 |     3 |       |     2   (0)| 00:00:01 |
|   8 |       SORT AGGREGATE                         |               |     1 |     3 |       |         |             |
|   9 |        FIRST ROW                             |               |     1 |     3 |       |     2   (0)| 00:00:01 |
|* 10 |         INDEX RANGE SCAN (MIN/MAX)           | IX_TEST_A     |     1 |     3 |       |     2   (0)| 00:00:01 |
|* 11 |       RECURSIVE WITH PUMP                    |               |       |       |       |         |             |
|  12 |     COLLECTION ITERATOR SUBQUERY FETCH       |               |  8168 | 16336 |       |    28   (0)| 00:00:01 |
|* 13 |      COUNT STOPKEY                           |               |       |       |       |         |             |
|* 14 |       INDEX RANGE SCAN DESCENDING            | IX_XT_TEST_AB |  2308 | 64624 |       |     8   (0)| 00:00:01 |
|* 15 |    TABLE ACCESS BY USER ROWID                | XT_TEST       |   692 | 22144 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

  10 - access(&quot;T1&quot;.&quot;A&quot;&gt;:B1)
  11 - filter(&quot;A&quot; IS NOT NULL)
  13 - filter(ROWNUM&lt;=5)
  14 - access(&quot;TT&quot;.&quot;A&quot;=:B1)
  15 - access(CHARTOROWID(VALUE(KOKBF$)))


Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        166  consistent gets
          0  physical reads
          0  redo size
       7523  bytes sent via SQL*Net to client
        519  bytes received via SQL*Net from client
         11  SQL*Net roundtrips to/from client
         33  sorts (memory)
          0  sorts (disk)
        150  rows processed
&lt;/pre&gt;
Аналогично можно через lateral:
&lt;pre class=&quot;brush: sql&quot;&gt;alter session set events &#39;22829 trace name context forever&#39;;
with t_unique( a ) as (
              select min(t1.a)
              from xt_test t1
              union all
              select (select min(t1.a) from xt_test t1 where t1.a&gt;t.a)
              from t_unique t
              where a is not null
)
select/*+ use_nl(rids tt) */ *
from t_unique v
    ,lateral(
              select/*+ index_desc(tt ix_xt_test_ab) */ tt.*
              from xt_test tt
              where tt.a=v.a
                and rownum&lt;=5
              order by tt.a, b desc
     ) r
order by r.a,r.b desc
&lt;/pre&gt;
В целом, конечно, можно было обойтись и без опасной сортировки, а взять и воспользоваться xmltable вместо table с передачей параметра сразу во внутренний подзапрос, но это чуток потяжелее чем обычный table.</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/500909580743469682/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/09/distinct-values-topn.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/500909580743469682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/500909580743469682'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/09/distinct-values-topn.html' title='Удивительная оптимизация получения distinct values из индекса, а также TopN для каждого'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-542924772080998361</id><published>2012-09-14T01:13:00.001+03:00</published><updated>2012-09-29T14:57:10.549+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="constraints"/><category scheme="http://www.blogger.com/atom/ns#" term="create constraint in parallel"/><category scheme="http://www.blogger.com/atom/ns#" term="foreign key"/><category scheme="http://www.blogger.com/atom/ns#" term="index range scan"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="parallel execution"/><category scheme="http://www.blogger.com/atom/ns#" term="parallel_index"/><title type='text'>Включение parallel для index range scan и создания констрейнтов</title><content type='html'>Сегодня нужно было ускорить большую разовую выгрузку(вообще был &quot;insert/*+append*/ select&quot;, но это не суть важно в данном контексте): большая не секционированная таблица, достаточно хорошая селективность по индексу( ~1.2%), больше 95% времени идет на lookup в таблицу из индекса. Один только индекс размером 44ГБ...&lt;br /&gt;
&lt;br /&gt;
Изначальный запрос был вида:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select t_big.*
from t_big
where t_big.a=:a
&lt;/pre&gt;Естественно, сразу захотелось распараллелить, но index range scan не идет в параллели, поэтому пришлось прибегнуть к небольшому ухищрению, которое позволило ускорить выполнение более чем в 13 раз при установке DOP в 16!&lt;br /&gt;
&lt;br /&gt;
Метод прост: т.к.вычитка из индекса достаточно быстрая, то просто читаем и материализуем rowid через IRS, и затем уже в параллели идем к таблице через TABLE ACCESS BY USER ROWID.&lt;br /&gt;
&lt;br /&gt;
Окончательный запрос:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;with rids as(
            select--+ materialize
               rowid rid
            from t_big t1
            where t1.a=:a
)
select/*+ use_nl(rids t_big) */ t_big.*
from t_big, rids
where t_big.rowid=rids.rid
&lt;/pre&gt;&lt;br /&gt;
&lt;b&gt;Создание констрейнтов в параллели:&lt;/b&gt;&lt;br /&gt;
По умолчанию при создании констрейнтов они валидируются не распараллеливаясь, что существенно замедляет процесс. Особенно учитывая, что обычно это происходит в технологические перерывы и ресурсов полно.. Решается же проблема просто: создавать их нужно с &lt;b&gt;&lt;i&gt;enable novalidate&lt;/i&gt;&lt;/b&gt;, и лишь затем отдельно включать enable validate:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;alter table t1 
   add constraint fk_t1
   foreign key(a)
   references t2(a)
   enable novalidate;
alter table t1 
   modify constraint fk_t1
   enable validate;
&lt;/pre&gt;&lt;b&gt;UPD:&lt;/b&gt; Исправил на enable novalidate, т.к. как правильно заметил &lt;a href=&quot;http://timurakhmadeev.wordpress.com/&quot;&gt;Тимур&lt;/a&gt; c disable не будет работать с unique и foreign key, а будет только для check constraints.</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/542924772080998361/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/09/parallel-index-range-scan.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/542924772080998361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/542924772080998361'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/09/parallel-index-range-scan.html' title='Включение parallel для index range scan и создания констрейнтов'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-6014598972351763584</id><published>2012-08-23T22:20:00.000+03:00</published><updated>2012-08-23T22:20:30.444+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="recursive sessions"/><title type='text'>О рекурсивных сессиях</title><content type='html'>Отличная статья от Танела Поддера: 
http://tech.e2sn.com/oracle/oracle-internals-and-architecture/recursive-sessions-and-ora-00018-maximum-number-of-sessions-exceeded</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/6014598972351763584/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/08/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/6014598972351763584'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/6014598972351763584'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/08/blog-post.html' title='О рекурсивных сессиях'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-6219595842578364230</id><published>2012-08-11T00:42:00.000+03:00</published><updated>2013-04-26T22:11:59.423+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="trace 10046"/><category scheme="http://www.blogger.com/atom/ns#" term="trace levels"/><title type='text'>Трассировка Event 10046, уровни 16,32,64</title><content type='html'>Christian Antognini &lt;a href=&quot;http://www.antognini.ch/2012/08/event-10046-full-list-of-levels/&quot;&gt;опубликовал полный список уровней для 10046-й трассы&lt;/a&gt;. &lt;br /&gt;
Утащу к себе, пока не запомню :)  &lt;h2&gt;Repost: Christian Antognini. &quot;Event 10046 – Full List of Levels&quot;&lt;/h2&gt;&lt;p&gt;Extended SQL trace (a.k.a. debugging event 10046 at a level higher than 1) is one of the key features provided by Oracle to troubleshoot applications using Oracle Database. For many years the available levels were always the same (4, 8 and 12). In fact, since I wrote &lt;a title=&quot;Tracing Bind Variables and Waits&quot; href=&quot;http://www.antognini.ch/papers/Tracing_Bind_Variables_and_Waits_20000507.pdf&quot; target=&quot;_blank&quot;&gt;my first paper&lt;/a&gt; about it in May 2000 and the release of 11g nothing changed.&lt;/p&gt;&lt;p&gt;With 11g, as I described in &lt;a title=&quot;11g New Feature in DBMS_MONITOR&quot; href=&quot;http://www.antognini.ch/2009/02/11g-new-feature-in-dbms_monitor/&quot; target=&quot;_blank&quot;&gt;this post&lt;/a&gt;, new levels (16 and 32) were introduced.&lt;/p&gt;&lt;p&gt;More recently, with the introduction of the &lt;a title=&quot;  Bug 8328200  Misleading or excessive STAT# lines for SQL_TRACE / 10046 &quot; href=&quot;https://support.oracle.com/epmos/faces/ui/km/DocContentDisplay.jspx?id=8328200.8&quot; target=&quot;_blank&quot;&gt;fix for bug 8328200&lt;/a&gt;, a new one was added to the list (64).&lt;/p&gt;&lt;p&gt;So, I thought it was time to publish the current list of available levels…&lt;/p&gt;&lt;table border=&quot;1&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;&lt;strong&gt;Level&lt;/strong&gt;&lt;/th&gt; &lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;0&lt;/td&gt; &lt;td&gt;The debugging event is disabled.&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;1&lt;/td&gt; &lt;td&gt;The debugging event is enabled. For each processed database call, the following information is given: SQL statement, response time, service time, number of processed rows, number of logical reads, number of physical reads and writes, execution plan, and little additional information.&lt;br /&gt;
Up to 10.2 an execution plan is written to the trace file only when the cursor it is associated with is closed. The execution statistics associated to it are values aggregated over all executions.&lt;br /&gt;
As of 11.1 an execution plan is written to the trace file only after the first execution of every cursor. The execution statistics associated to it are the ones of the first execution only. &lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;4&lt;/td&gt; &lt;td&gt;As in level 1, with additional information about bind variables. Mainly, the data type, its precision, and the value used for each execution.&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;8&lt;/td&gt; &lt;td&gt;As in level 1, plus detailed information about wait time. For each wait experienced during the processing, the following information is given: the name of the wait event, the duration, and a few additional parameters identifying the resource that has been waited for.&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;16&lt;/td&gt; &lt;td&gt;As in level 1, plus the execution plans information is written to the trace file for each execution. Available as of 11.1 only.&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;32&lt;/td&gt; &lt;td&gt;As in level 1, but without the execution plans information. Available as of 11.1 only.&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;64&lt;/td&gt; &lt;td&gt;As in level 1, plus the execution plans information might be written for executions following the first one. The condition is that, since the last write of execution plans information, a particular cursor consumed at least one additional minute of DB time. This level is interesting in two cases. First, when the information about the first execution is not enough for analysing a specific issue. Second, when the overhead of writing the information about every execution (level 16) is too high. Generally available as of 11.2.0.2  only.&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;In addition to the levels described in the previous table, you can also combine the levels 4 and 8 with every other level greater than 1. For example:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Level 12 (4 + 8): simultaneously enable level 4 and level 8.&lt;/li&gt;
&lt;li&gt;Level 28 (4 + 8 + 16): simultaneously enable level 4, level 8 and level 16.&lt;/li&gt;
&lt;li&gt;Level 68 (4 + 64): simultaneously enable level 4 and level 64.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;If you are using dbms_monitor or dbms_session for enabling extended SQL trace, here is the mapping between the levels and the parameters:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Level 4: waits=FALSE, binds=TRUE, plan_stat=&amp;#8217;first_execution&amp;#8217;&lt;/li&gt;
&lt;li&gt;Level 8: waits=TRUE, binds=FALSE, plan_stat=&amp;#8217;first_execution&amp;#8217;&lt;/li&gt;
&lt;li&gt;Level 16: waits=FALSE, binds=FALSE, plan_stat=&amp;#8217;all_executions&amp;#8217;&lt;/li&gt;
&lt;li&gt;Level 32: waits=FALSE, binds=FALSE, plan_stat=&amp;#8217;never&amp;#8217;&lt;/li&gt;
&lt;li&gt;Level 64: not available yet&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;As you can see from the previous list, it is not possible to enable level 64 through dbms_monitor and dbms_session. Hence, statements like the following ones or ORADEBUG have to be used:&lt;/p&gt;&lt;p&gt;&lt;pre class=&quot;brush: sql&quot;&gt;alter session set events &#39;10046 trace name context forever, level 64&#39;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;&lt;pre class=&quot;brush: sql&quot;&gt;alter session set events &#39;sql_trace wait=false, bind=false, plan_stat=adaptive&#39;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;I really hope that this limitation will be removed very soon.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/6219595842578364230/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/08/event-10046-163264.html#comment-form' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/6219595842578364230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/6219595842578364230'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/08/event-10046-163264.html' title='Трассировка Event 10046, уровни 16,32,64'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-82649993831506479</id><published>2012-08-10T23:41:00.000+03:00</published><updated>2012-08-10T23:41:31.517+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="docs.oracle.com"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="unwrap"/><category scheme="http://www.blogger.com/atom/ns#" term="wrap"/><category scheme="http://www.blogger.com/atom/ns#" term="документация oracle"/><title type='text'>Ссылка на онлайн unwrapper в документации Oracle</title><content type='html'>&lt;p&gt;Все, конечно, знают про unwrapper&#39;ы и многие даже пробовали свой написать (и я в том числе, после после презентации Pete Finnigan&#39;а :), но тем не менее забавно, что Oracle в документации к 11.2 прямо-таки &quot;громогласно&quot; заявляет о том, что ничего unwrap от просмотра не защищает, но еще и прямую ссылку дает на online unwrapper :) &lt;/p&gt;
&lt;style type=&quot;text/css&quot;&gt;
div.infoboxnote, div.infoboxnotewarn, div.infoboxnotealso {
margin-top: 4ex;
margin-right: 10%;
margin-left: 10%;
margin-bottom: 4ex;
padding: 0.25em;
border-top: 1pt solid gray;
border-bottom: 1pt solid gray;
font-family: Tahoma, sans-serif;
color: #222;
font-size: small;
display: block;
}
.IND p, .IND div, .IND table {
max-width: 70em;
}
.IND {
line-height: 1.5;
}
&lt;/style&gt;

&lt;a href=&quot;http://docs.oracle.com/cd/E11882_01/appdev.112/e10472/wrap.htm&quot;&gt;&lt;b&gt;11.2 PL/SQL Source Text Wrapping&lt;/b&gt;&lt;/a&gt;:
&lt;div class=&quot;infoboxnote&quot;&gt;
&lt;p class=&quot;notep1&quot;&gt;Note:&lt;/p&gt;
Wrapping text does not prevent anyone from displaying it with a utility such as:
&lt;p&gt;&lt;code&gt;&lt;a href=&quot;http://www.codecheck.info/UnwrapIt/&quot;&gt;http://www.codecheck.info/UnwrapIt/&lt;/a&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;For high-assurance security, use Oracle Database Vault, described in &lt;a class=&quot;olink DVADM&quot; href=&quot;http://docs.oracle.com/cd/E11882_01/appdev.112/server.112/e23090/toc.htm&quot;&gt;&lt;span class=&quot;italic&quot;&gt;Oracle Database Vault Administrator&#39;s Guide&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;

И для сравнения прогресс документации от версии к версии о возможности unwrap&#39;а:
&lt;ul&gt;
&lt;li&gt;В &lt;a href=&quot;http://docs.oracle.com/cd/B10501_01/appdev.920/a96624/c_wrap.htm#3209&quot;&gt;9.2&lt;/a&gt; все скрывает надежно, кроме литералов и названий переменных, таблиц, колонок:
&lt;blockquote&gt;
String literals, number literals, and names of variables, tables, and columns remain in plain text within the wrapped file. Wrapping a procedure helps to hide the algorithm and prevent reverse-engineering, but it is not a way to hide passwords or table names that you want to be secret.
&lt;/blockquote&gt;
&lt;/li&gt;

&lt;li&gt;А в &lt;a href=&quot;http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/wrap.htm#sthref3172&quot;&gt;10.2&lt;/a&gt; уже защищено лишь от бóльшего количества пользователей, но все-таки затрудняет реверс-инжиниринг!
&lt;blockquote&gt;
Although wrapping a compilation unit helps to hide the algorithm and makes reverse-engineering difficult, Oracle Corporation does not recommend it as a secure method for hiding passwords or table names. Obfuscating a PL/SQL unit prevents most users from examining the source code, but might not stop all attempts.
&lt;/blockquote&gt;
&lt;/li&gt;

&lt;li&gt;В &lt;a href=&quot;http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/wrap.htm#BEHGBJAA&quot;&gt;11.1&lt;/a&gt; как-то скромно и скучно:
&lt;blockquote&gt;Wrapping is not a secure method for hiding passwords or table names.

Wrapping a PL/SQL unit prevents most users from examining the source code, but might not stop all of them.
&lt;/blockquote&gt;
&lt;/li&gt;

&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/82649993831506479/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/08/unwrapper-oracle.html#comment-form' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/82649993831506479'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/82649993831506479'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/08/unwrapper-oracle.html' title='Ссылка на онлайн unwrapper в документации Oracle'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-8256316365249657433</id><published>2012-08-08T23:42:00.000+03:00</published><updated>2012-08-08T23:42:08.572+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="perl"/><category scheme="http://www.blogger.com/atom/ns#" term="regexp"/><category scheme="http://www.blogger.com/atom/ns#" term="regexp replace substring"/><category scheme="http://www.blogger.com/atom/ns#" term="sprintf"/><title type='text'>Регулярные выражения Oracle с вычисляемой заменяемой частью</title><content type='html'>&lt;a href=&quot;http://www.sql.ru/forum/actualthread.aspx?tid=960945&quot;&gt;Интересная тема&lt;/a&gt; с возможными решениями двух стандартных задач:&lt;br /&gt;
1) sprintf в oracle в SQL&lt;br /&gt;
2) замена по регулярке с вычисляемой заменяемой частью(а ля модификатор &quot;e&quot; в perl)</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/8256316365249657433/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/08/oracle.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/8256316365249657433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/8256316365249657433'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/08/oracle.html' title='Регулярные выражения Oracle с вычисляемой заменяемой частью'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-2695020571118859481</id><published>2012-07-30T23:25:00.001+03:00</published><updated>2012-07-30T23:32:52.908+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="invalidation"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle undocumented behaviour"/><category scheme="http://www.blogger.com/atom/ns#" term="result_cache"/><title type='text'>When oracle invalidates result_cache function results without any changes in objects on which depends</title><content type='html'>On our production servers we have simple function with result_cache, like this:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;create or replace function f_rc(p_id number) return number result_cache
is
  ret number;
begin
  select t.val into ret from rc_table t where t.id=p_id;
  return ret;
exception 
  when no_data_found then 
     return null;
end;
/
&lt;/pre&gt;And its results frequently invalidates without any changes in table or function. I found only 2 cases when oracle invalidates result_cache results without any changes in table:&lt;br /&gt;
1. &quot;select for update&quot; from this table with commit;&lt;br /&gt;
2. deletion of unrelated rows from parent table if there is unindexed foreign key with &quot;on delete cascade&quot;.&lt;br /&gt;
I test it on 11.2.0.1, 11.2.0.3, on solaris x64 and windows. Test cases for this i will show below.&lt;br /&gt;
But none of them can be the cause of our situation: we have no unindexed fk, and even if i lock all rows with &quot;select for update&quot;, it still does not stop invalidating.&lt;br /&gt;
In what other cases this happens? Am I right that the oracle does not track any changes, but the captures of the locks and &quot;commits&quot;?&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;tables and function&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;drop function f_rc;
drop table rc_table purge;
drop table rc_parent purge;


create table rc_parent(id primary key, val) as
select level,level from dual connect by level&lt;=10;

create table rc_table(id primary key,parent,val) as 
select level,level,level from dual connect by level&lt;=10;

create index ix_rc_table_parent on rc_table(parent);
alter table rc_table add constraint fk_parent foreign key(parent) references rc_parent(id);

create or replace function f_rc(p_id number) return number result_cache
is
  ret number;
begin
  select t.val into ret from rc_table t where t.id=p_id;
  dbms_output.put_line(&#39;fired&#39;);
  return ret;
exception when no_data_found then return null;
end;
/
&lt;/pre&gt;
&lt;/div&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Test case with &#39;select for update&#39;&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;-- first execution:
DB11G/XTENDER&gt; select f_rc(1) from dual;

   F_RC(1)
----------
         1

1 row selected.

fired
-- checking result_cache 
DB11G/XTENDER&gt; /

   F_RC(1)
----------
         1

1 row selected.
-- execute in another session: select * from rc_table for update; 
-- and check again:
DB11G/XTENDER&gt; /

   F_RC(1)
----------
         1

1 row selected.
-- result valid:
DB11G/XTENDER&gt; col name form a50
DB11G/XTENDER&gt; select id,type,status,name,namespace,creation_timestamp,scn from v$result_cache_objects;

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40643967
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967
         1 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:31:35   40643967

3 rows selected.
DB11G/XTENDER&gt; save rc_objects
Created file rc_objects.sql
-- rollback in another session after &quot;select for update&quot; and check again:
-- result still valid:
DB11G/XTENDER&gt; /

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40643967
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967
         1 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:31:35   40643967

3 rows selected.
DB11G/XTENDER&gt; select f_rc(1) from dual;

   F_RC(1)
----------
         1

1 row selected.

DB11G/XTENDER&gt; save test replace
Wrote file test.sql
-- again &quot;select * from rc_table for update;&quot; in another session but now with &quot;commit;&quot;
-- check again:
DB11G/XTENDER&gt; @rc_objects


        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40644109
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967
         1 Result     Invalid   &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:31:35   40643967

3 rows selected.
-- scn changed! and result is invalid now!
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Unindexed fk&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;-- getting new result
DB11G/XTENDER&gt; @test

   F_RC(1)
----------
         1

1 row selected.

fired
-- execute in another session: insert into rc_parent values(-1,-1); 
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40644109            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967            1          0
         3 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:41:53   40644522            2          0

-- new result is valid
-- execute in another session: rollback; 
DB11G/XTENDER&gt; @test

   F_RC(1)
----------
         1

DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40644109            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967            1          0
         3 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:41:53   40644522            2          1

-- again insert in another session, but now with commit: 
--    insert into rc_parent values(-1,-1); 
--    commit;
-- still valid:
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40644109            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967            1          0
         3 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:41:53   40644522            2          1

-- in another session: delete from rc_parent where id=-1; rollback;
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40644109            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967            1          0
         3 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:41:53   40644522            2          2

-- in another session: delete from rc_parent where id=-1; commit;
-- still valid:
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40644109            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967            1          0
         3 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:41:53   40644522            2          2

-- now without index:
DB11G/XTENDER&gt; drop index ix_rc_table_parent;

Index dropped.

DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40644745            0          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967            0          0
         3 Result     Invalid   &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:41:53   40644522            2          3

4 rows selected.

DB11G/XTENDER&gt; @test

   F_RC(1)
----------
         1

1 row selected.

fired
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40644745            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967            1          0
         4 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:51:27   40644759            2          0
         3 Result     Invalid   &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:41:53   40644522            2          3
-- again insert with commit in another session
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40644745            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967            1          0
         4 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:51:27   40644759            2          0
         3 Result     Invalid   &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:41:53   40644522            2          3
-- again delete with commit:
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:31:35   40644745            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:31:35   40643967            1          0
         4 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:51:27   40644759            2          0
         3 Result     Invalid   &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:41:53   40644522            2          3
-- now with &quot;on delete cascade&quot;:
DB11G/XTENDER&gt; alter table rc_table drop constraint fk_parent;

Table altered.
DB11G/XTENDER&gt; alter table rc_table add constraint fk_parent foreign key(parent) references rc_parent(id) on delete cascade;

Table altered.
DB11G/XTENDER&gt; exec dbms_result_cache.Flush;

PL/SQL procedure successfully completed.
DB11G/XTENDER&gt; @test

   F_RC(1)
----------
         1

1 row selected.

fired
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:58:53   40645010            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:58:53   40645010            1          0
         1 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:58:53   40645010            2          0
-- again in another session: insert into rc_parent values(-1,-1);commit;delete from rc_parent where id=-1;commit;
-- checking:
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 01:58:53   40645202            0          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 01:58:53   40645010            0          0
         1 Result     Invalid   &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 01:58:53   40645010            2          0
-- Result is invalid now!
DB11G/XTENDER&gt; -- now with index:
DB11G/XTENDER&gt; create index ix_rc_table_parent on rc_table(parent);

Index created.

DB11G/XTENDER&gt; exec dbms_result_cache.Flush;

PL/SQL procedure successfully completed.

DB11G/XTENDER&gt; @test

   F_RC(1)
----------
         1

1 row selected.

fired
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 02:23:13   40654418            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 02:23:13   40654418            1          0
         1 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 02:23:13   40654418            2          0

3 rows selected.
-- again in another session: insert into rc_parent values(-1,-1);commit;delete from rc_parent where id=-1;commit;
DB11G/XTENDER&gt; @rc_objects

        ID TYPE       STATUS    NAME                                               NAMES CREATION_TIMESTAMP     SCN DEPEND_COUNT SCAN_COUNT
---------- ---------- --------- -------------------------------------------------- ----- ------------------- ---------- ------------ ----------
         2 Dependency Published XTENDER.RC_TABLE                                         29.07.2012 02:23:13   40654418            1          0
         0 Dependency Published XTENDER.F_RC                                             29.07.2012 02:23:13   40654418            1          0
         1 Result     Published &quot;XTENDER&quot;.&quot;F_RC&quot;::8.&quot;F_RC&quot;#fac892c7867b54c6 #1     PLSQL 29.07.2012 02:23:13   40654418            2          0

3 rows selected.
-- Result still is valid.
&lt;/pre&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/2695020571118859481/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/07/when-oracle-invalidates-resultcache.html#comment-form' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/2695020571118859481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/2695020571118859481'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/07/when-oracle-invalidates-resultcache.html' title='When oracle invalidates result_cache function results without any changes in objects on which depends'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-3098674461291285827</id><published>2012-07-21T00:48:00.000+03:00</published><updated>2012-07-21T00:48:06.937+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="clob"/><category scheme="http://www.blogger.com/atom/ns#" term="ora-600"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="задачка"/><title type='text'>Интересный вопрос от Валентина Никотина</title><content type='html'>Тестовая таблица:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;create table tclob(c clob);
&lt;/pre&gt;&lt;br /&gt;
Что будет выведено кодом из нижеследующих блоков с rollback и без:&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Задача 1&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;declare
  cl1 clob;
  cl2 clob;
  cl3 clob;
  cl4 clob;
begin
  cl1:=&#39;1&#39;;
  insert into tclob values(cl1) returning c into cl2;
  cl3:=cl2;
  dbms_lob.append(cl3,&#39;2&#39;);
  select c into cl4 from tclob;
--  rollback;

  dbms_output.put_line(cl1);
  dbms_output.put_line(cl2);
  dbms_output.put_line(cl3);
  dbms_output.put_line(cl4);
end;
/
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Задача 2&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;declare
  cl1 clob;
  cl2 clob;
  cl3 clob;
  cl4 clob;
begin
  cl1 := &#39;1&#39;;
  insert into tclob values (cl1) returning c into cl2;
  cl3 := cl2;
  dbms_lob.append(cl2, &#39;2&#39;);
  select c into cl4 from tclob;
--  rollback;

  dbms_output.put_line(cl1);
  dbms_output.put_line(cl2);
  dbms_output.put_line(cl3);
  dbms_output.put_line(cl4);
end;
/
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Задача 3&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;declare
  cl1 clob;
  cl2 clob;
  cl3 clob;
  cl4 clob;
begin
  cl1 := &#39;1&#39;;
  insert into tclob values (cl1) returning c into cl2;
  cl3 := cl2;
  dbms_lob.append(cl2, &#39;2&#39;);
  dbms_lob.append(cl3, &#39;3&#39;);
  select c into cl4 from tclob;
--  rollback;

  dbms_output.put_line(cl1);
  dbms_output.put_line(cl2);
  dbms_output.put_line(cl3);
  dbms_output.put_line(cl4);
end;
/
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Задача 4&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;declare
  cl1 clob;
  cl2 clob;
  cl3 clob;
  cl4 clob;
begin
  cl1 := &#39;1&#39;;
  insert into tclob values (cl1) returning c into cl2;
  cl3 := cl2;
  dbms_lob.append(cl2, &#39;22&#39;);
  dbms_lob.append(cl3, &#39;3&#39;);
  dbms_lob.append(cl2, &#39;44&#39;);
  select c into cl4 from tclob;
--  rollback;
  dbms_output.put_line(cl1);
  dbms_output.put_line(cl2);
  dbms_output.put_line(cl3);
  dbms_output.put_line(cl4);
end;
/
&lt;/pre&gt;&lt;/div&gt;Проверьте и на винде, и на солярке/линуксе :)&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Объяснение&quot;&gt;Ясно, что этот баг платформозависим и что дело в особенностях работы с памятью. Ответ кроется в том, что у cl3 и cl2 не синхронизированы длины, т.е. Oracle &quot;забывает&quot; изменить длины всех остальных переменных, указывающих на этот clob, а т.к. каждая операция изменения cl2/cl3 фактически изменяет одно и то же, то &quot;лишнее&quot; перезаписывается.&lt;br /&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/3098674461291285827/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/07/blog-post_21.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/3098674461291285827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/3098674461291285827'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/07/blog-post_21.html' title='Интересный вопрос от Валентина Никотина'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-9195786845516542204</id><published>2012-07-14T00:37:00.002+03:00</published><updated>2012-07-14T00:37:34.695+03:00</updated><title type='text'>Ура! Сын родился!</title><content type='html'>Теперь у нас полная семья - и доча и сын :)&lt;br /&gt;
Уррррррррраааааа! :)</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/9195786845516542204/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/07/blog-post.html#comment-form' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/9195786845516542204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/9195786845516542204'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/07/blog-post.html' title='Ура! Сын родился!'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-7907757324411762410</id><published>2012-06-30T01:03:00.000+03:00</published><updated>2012-10-04T22:36:56.024+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dml allocation latch"/><category scheme="http://www.blogger.com/atom/ns#" term="gv$lock"/><category scheme="http://www.blogger.com/atom/ns#" term="latch free"/><category scheme="http://www.blogger.com/atom/ns#" term="latches"/><category scheme="http://www.blogger.com/atom/ns#" term="optimization"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="v$lock"/><title type='text'>Большое количество latch free: dml allocation latch при конкурентных запросах к v$lock</title><content type='html'>Проблема эта в общем-то старая, но только сейчас благодаря книге &quot;Oracle Core&quot; Джонатана Льюиса удалось узнать в чем собственно проблема и справиться с ней. &lt;br /&gt;
Цитата из главы &quot;&lt;b&gt;Latches for lock&lt;/b&gt;&quot;:&lt;br /&gt;
&lt;blockquote&gt;&lt;i&gt;&lt;br /&gt;
If the enqueue resource is in place already, then pick a row from the relevant enqueue structure (x$ksqeq, et al.), but to do this you have to get the associated enqueue latch to stop other people from picking the same enqueue row at the same time. The latch you need to acquire depends on the specific type of enqueue you are using; for example, if you want a row from x$ksqeq  you need to get the enqueue latch but &lt;u&gt;for a row from &lt;b&gt;x$ktadm&lt;/b&gt; you need to get the dml allocation latch&lt;/u&gt;. Drop this latch as soon as you have made the enqueue row safe. &lt;br /&gt;
&lt;/i&gt;&lt;/blockquote&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
А эта fixed таблица и есть в v$lock, это я многократно видел в планах c ней:&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;План&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; explain plan for select * from v$lock;

Explained.

Elapsed: 00:00:00.28
DB11G/XTENDER&gt; @xplan

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------

Plan hash value: 3074737110

--------------------------------------------------------------------------------------------
| Id  | Operation                | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |                 |     1 |   131 |     1 (100)| 00:00:01 |
|   1 |  NESTED LOOPS            |                 |     1 |   131 |     1 (100)| 00:00:01 |
|*  2 |   HASH JOIN              |                 |     1 |    98 |     1 (100)| 00:00:01 |
|*  3 |    FIXED TABLE FULL      | X$KSUSE         |     1 |    30 |     0   (0)| 00:00:01 |
|   4 |    VIEW                  | GV$_LOCK        |    10 |   680 |     0   (0)| 00:00:01 |
|   5 |     UNION-ALL            |                 |       |       |            |          |
|*  6 |      FILTER              |                 |       |       |            |          |
|   7 |       VIEW               | GV$_LOCK1       |     2 |   136 |     0   (0)| 00:00:01 |
|   8 |        UNION-ALL         |                 |       |       |            |          |
|*  9 |         FIXED TABLE FULL | X$KDNSSF        |     1 |    94 |     0   (0)| 00:00:01 |
|* 10 |         FIXED TABLE FULL | X$KSQEQ         |     1 |    94 |     0   (0)| 00:00:01 |
|* 11 |      FIXED TABLE FULL    | X$KTADM         |     1 |    94 |     0   (0)| 00:00:01 |
|* 12 |      FIXED TABLE FULL    | X$KTATRFIL      |     1 |    94 |     0   (0)| 00:00:01 |
|* 13 |      FIXED TABLE FULL    | X$KTATRFSL      |     1 |    94 |     0   (0)| 00:00:01 |
|* 14 |      FIXED TABLE FULL    | X$KTATL         |     1 |    94 |     0   (0)| 00:00:01 |
|* 15 |      FIXED TABLE FULL    | X$KTSTUSC       |     1 |    94 |     0   (0)| 00:00:01 |
|* 16 |      FIXED TABLE FULL    | X$KTSTUSS       |     1 |    94 |     0   (0)| 00:00:01 |
|* 17 |      FIXED TABLE FULL    | X$KTSTUSG       |     1 |    94 |     0   (0)| 00:00:01 |
|* 18 |      FIXED TABLE FULL    | X$KTCXB         |     1 |    94 |     0   (0)| 00:00:01 |
|* 19 |   FIXED TABLE FIXED INDEX| X$KSQRS (ind:1) |     1 |    33 |     0   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
&lt;/pre&gt;&lt;/div&gt;Теперь уже зная корень проблемы, остается только узнать можно ли избавиться от лишних обращений к X$KTADM, что интуитивно кажется возможным учитывая, что она часть &quot;union all&quot;.&lt;br /&gt;
То есть надо было &quot;разобрать&quot; этот v$lock, чтобы получить полный текст запроса. Для этого я сначала получил текст запроса через трассировку 10053:&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Unparsed query&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;SELECT &quot;S&quot;.&quot;INST_ID&quot; &quot;INST_ID&quot;,
       &quot;L&quot;.&quot;LADDR&quot; &quot;ADDR&quot;,
       &quot;L&quot;.&quot;KADDR&quot; &quot;KADDR&quot;,
       &quot;S&quot;.&quot;KSUSENUM&quot; &quot;SID&quot;,
       &quot;R&quot;.&quot;KSQRSIDT&quot; &quot;TYPE&quot;,
       &quot;R&quot;.&quot;KSQRSID1&quot; &quot;ID1&quot;,
       &quot;R&quot;.&quot;KSQRSID2&quot; &quot;ID2&quot;,
       &quot;L&quot;.&quot;LMODE&quot; &quot;LMODE&quot;,
       &quot;L&quot;.&quot;REQUEST&quot; &quot;REQUEST&quot;,
       &quot;L&quot;.&quot;CTIME&quot; &quot;CTIME&quot;,
       DECODE(&quot;L&quot;.&quot;LMODE&quot;, 0, 0, &quot;L&quot;.&quot;BLOCK&quot;) &quot;BLOCK&quot;
  FROM (SELECT &quot;GV$_LOCK&quot;.&quot;LADDR&quot;   &quot;LADDR&quot;,
               &quot;GV$_LOCK&quot;.&quot;KADDR&quot;   &quot;KADDR&quot;,
               &quot;GV$_LOCK&quot;.&quot;SADDR&quot;   &quot;SADDR&quot;,
               &quot;GV$_LOCK&quot;.&quot;RADDR&quot;   &quot;RADDR&quot;,
               &quot;GV$_LOCK&quot;.&quot;LMODE&quot;   &quot;LMODE&quot;,
               &quot;GV$_LOCK&quot;.&quot;REQUEST&quot; &quot;REQUEST&quot;,
               &quot;GV$_LOCK&quot;.&quot;CTIME&quot;   &quot;CTIME&quot;,
               &quot;GV$_LOCK&quot;.&quot;BLOCK&quot;   &quot;BLOCK&quot;
          FROM ( (SELECT USERENV(&#39;INSTANCE&#39;) &quot;INST_ID&quot;,
                        &quot;V$_LOCK1&quot;.&quot;LADDR&quot; &quot;LADDR&quot;,
                        &quot;V$_LOCK1&quot;.&quot;KADDR&quot; &quot;KADDR&quot;,
                        &quot;V$_LOCK1&quot;.&quot;SADDR&quot; &quot;SADDR&quot;,
                        &quot;V$_LOCK1&quot;.&quot;RADDR&quot; &quot;RADDR&quot;,
                        &quot;V$_LOCK1&quot;.&quot;LMODE&quot; &quot;LMODE&quot;,
                        &quot;V$_LOCK1&quot;.&quot;REQUEST&quot; &quot;REQUEST&quot;,
                        &quot;V$_LOCK1&quot;.&quot;CTIME&quot; &quot;CTIME&quot;,
                        &quot;V$_LOCK1&quot;.&quot;BLOCK&quot; &quot;BLOCK&quot;
                   FROM (SELECT &quot;GV$_LOCK1&quot;.&quot;LADDR&quot;   &quot;LADDR&quot;,
                                &quot;GV$_LOCK1&quot;.&quot;KADDR&quot;   &quot;KADDR&quot;,
                                &quot;GV$_LOCK1&quot;.&quot;SADDR&quot;   &quot;SADDR&quot;,
                                &quot;GV$_LOCK1&quot;.&quot;RADDR&quot;   &quot;RADDR&quot;,
                                &quot;GV$_LOCK1&quot;.&quot;LMODE&quot;   &quot;LMODE&quot;,
                                &quot;GV$_LOCK1&quot;.&quot;REQUEST&quot; &quot;REQUEST&quot;,
                                &quot;GV$_LOCK1&quot;.&quot;CTIME&quot;   &quot;CTIME&quot;,
                                &quot;GV$_LOCK1&quot;.&quot;BLOCK&quot;   &quot;BLOCK&quot;
                           FROM ((SELECT &quot;X$KDNSSF&quot;.&quot;INST_ID&quot;   &quot;INST_ID&quot;,
                                         &quot;X$KDNSSF&quot;.&quot;ADDR&quot;      &quot;LADDR&quot;,
                                         &quot;X$KDNSSF&quot;.&quot;KSQLKADR&quot;  &quot;KADDR&quot;,
                                         &quot;X$KDNSSF&quot;.&quot;KSQLKSES&quot;  &quot;SADDR&quot;,
                                         &quot;X$KDNSSF&quot;.&quot;KSQLKRES&quot;  &quot;RADDR&quot;,
                                         &quot;X$KDNSSF&quot;.&quot;KSQLKMOD&quot;  &quot;LMODE&quot;,
                                         &quot;X$KDNSSF&quot;.&quot;KSQLKREQ&quot;  &quot;REQUEST&quot;,
                                         &quot;X$KDNSSF&quot;.&quot;KSQLKCTIM&quot; &quot;CTIME&quot;,
                                         &quot;X$KDNSSF&quot;.&quot;KSQLKLBLK&quot; &quot;BLOCK&quot;
                                    FROM SYS.&quot;X$KDNSSF&quot; &quot;X$KDNSSF&quot;
                                   WHERE BITAND(&quot;X$KDNSSF&quot;.&quot;KSSOBFLG&quot;, 1) &lt;&gt; 0
                                     AND (&quot;X$KDNSSF&quot;.&quot;KSQLKMOD&quot; &lt;&gt; 0 OR
                                          &quot;X$KDNSSF&quot;.&quot;KSQLKREQ&quot; &lt;&gt; 0)) 
                                 UNION ALL
                                 (SELECT &quot;X$KSQEQ&quot;.&quot;INST_ID&quot;   &quot;INST_ID&quot;,
                                         &quot;X$KSQEQ&quot;.&quot;ADDR&quot;      &quot;LADDR&quot;,
                                         &quot;X$KSQEQ&quot;.&quot;KSQLKADR&quot;  &quot;KADDR&quot;,
                                         &quot;X$KSQEQ&quot;.&quot;KSQLKSES&quot;  &quot;SADDR&quot;,
                                         &quot;X$KSQEQ&quot;.&quot;KSQLKRES&quot;  &quot;RADDR&quot;,
                                         &quot;X$KSQEQ&quot;.&quot;KSQLKMOD&quot;  &quot;LMODE&quot;,
                                         &quot;X$KSQEQ&quot;.&quot;KSQLKREQ&quot;  &quot;REQUEST&quot;,
                                         &quot;X$KSQEQ&quot;.&quot;KSQLKCTIM&quot; &quot;CTIME&quot;,
                                         &quot;X$KSQEQ&quot;.&quot;KSQLKLBLK&quot; &quot;BLOCK&quot;
                                    FROM SYS.&quot;X$KSQEQ&quot; &quot;X$KSQEQ&quot;
                                   WHERE BITAND(&quot;X$KSQEQ&quot;.&quot;KSSOBFLG&quot;, 1) &lt;&gt; 0
                                     AND (&quot;X$KSQEQ&quot;.&quot;KSQLKMOD&quot; &lt;&gt; 0 OR
                                          &quot;X$KSQEQ&quot;.&quot;KSQLKREQ&quot; &lt;&gt; 0))
                                ) &quot;GV$_LOCK1&quot;
                          WHERE &quot;GV$_LOCK1&quot;.&quot;INST_ID&quot; = USERENV(&#39;INSTANCE&#39;)
                         ) &quot;V$_LOCK1&quot;
                  )
                UNION ALL 
                  (SELECT &quot;X$KTADM&quot;.&quot;INST_ID&quot;   &quot;INST_ID&quot;,
                          &quot;X$KTADM&quot;.&quot;ADDR&quot;      &quot;LADDR&quot;,
                          &quot;X$KTADM&quot;.&quot;KSQLKADR&quot;  &quot;KADDR&quot;,
                          &quot;X$KTADM&quot;.&quot;KSQLKSES&quot;  &quot;SADDR&quot;,
                          &quot;X$KTADM&quot;.&quot;KSQLKRES&quot;  &quot;RADDR&quot;,
                          &quot;X$KTADM&quot;.&quot;KSQLKMOD&quot;  &quot;LMODE&quot;,
                          &quot;X$KTADM&quot;.&quot;KSQLKREQ&quot;  &quot;REQUEST&quot;,
                          &quot;X$KTADM&quot;.&quot;KSQLKCTIM&quot; &quot;CTIME&quot;,
                          &quot;X$KTADM&quot;.&quot;KSQLKLBLK&quot; &quot;BLOCK&quot;
                     FROM SYS.&quot;X$KTADM&quot; &quot;X$KTADM&quot; /*** 1 ***/
                    WHERE BITAND(&quot;X$KTADM&quot;.&quot;KSSOBFLG&quot;, 1) &lt;&gt; 0
                      AND (&quot;X$KTADM&quot;.&quot;KSQLKMOD&quot; &lt;&gt; 0 OR
                           &quot;X$KTADM&quot;.&quot;KSQLKREQ&quot; &lt;&gt; 0)
                  ) 
                UNION ALL
                  (SELECT &quot;X$KTATRFIL&quot;.&quot;INST_ID&quot;   &quot;INST_ID&quot;,
                          &quot;X$KTATRFIL&quot;.&quot;ADDR&quot;      &quot;LADDR&quot;,
                          &quot;X$KTATRFIL&quot;.&quot;KSQLKADR&quot;  &quot;KADDR&quot;,
                          &quot;X$KTATRFIL&quot;.&quot;KSQLKSES&quot;  &quot;SADDR&quot;,
                          &quot;X$KTATRFIL&quot;.&quot;KSQLKRES&quot;  &quot;RADDR&quot;,
                          &quot;X$KTATRFIL&quot;.&quot;KSQLKMOD&quot;  &quot;LMODE&quot;,
                          &quot;X$KTATRFIL&quot;.&quot;KSQLKREQ&quot;  &quot;REQUEST&quot;,
                          &quot;X$KTATRFIL&quot;.&quot;KSQLKCTIM&quot; &quot;CTIME&quot;,
                          &quot;X$KTATRFIL&quot;.&quot;KSQLKLBLK&quot; &quot;BLOCK&quot;
                     FROM SYS.&quot;X$KTATRFIL&quot; &quot;X$KTATRFIL&quot;
                    WHERE BITAND(&quot;X$KTATRFIL&quot;.&quot;KSSOBFLG&quot;, 1) &lt;&gt; 0
                      AND (&quot;X$KTATRFIL&quot;.&quot;KSQLKMOD&quot; &lt;&gt; 0 OR
                           &quot;X$KTATRFIL&quot;.&quot;KSQLKREQ&quot; &lt;&gt; 0)
                  ) 
                UNION ALL
                (SELECT &quot;X$KTATRFSL&quot;.&quot;INST_ID&quot;   &quot;INST_ID&quot;,
                        &quot;X$KTATRFSL&quot;.&quot;ADDR&quot;      &quot;LADDR&quot;,
                        &quot;X$KTATRFSL&quot;.&quot;KSQLKADR&quot;  &quot;KADDR&quot;,
                        &quot;X$KTATRFSL&quot;.&quot;KSQLKSES&quot;  &quot;SADDR&quot;,
                        &quot;X$KTATRFSL&quot;.&quot;KSQLKRES&quot;  &quot;RADDR&quot;,
                        &quot;X$KTATRFSL&quot;.&quot;KSQLKMOD&quot;  &quot;LMODE&quot;,
                        &quot;X$KTATRFSL&quot;.&quot;KSQLKREQ&quot;  &quot;REQUEST&quot;,
                        &quot;X$KTATRFSL&quot;.&quot;KSQLKCTIM&quot; &quot;CTIME&quot;,
                        &quot;X$KTATRFSL&quot;.&quot;KSQLKLBLK&quot; &quot;BLOCK&quot;
                   FROM SYS.&quot;X$KTATRFSL&quot; &quot;X$KTATRFSL&quot;
                  WHERE BITAND(&quot;X$KTATRFSL&quot;.&quot;KSSOBFLG&quot;, 1) &lt;&gt; 0
                    AND (&quot;X$KTATRFSL&quot;.&quot;KSQLKMOD&quot; &lt;&gt; 0 OR
                         &quot;X$KTATRFSL&quot;.&quot;KSQLKREQ&quot; &lt;&gt; 0)) 
                UNION ALL
                (SELECT &quot;X$KTATL&quot;.&quot;INST_ID&quot;   &quot;INST_ID&quot;,
                        &quot;X$KTATL&quot;.&quot;ADDR&quot;      &quot;LADDR&quot;,
                        &quot;X$KTATL&quot;.&quot;KSQLKADR&quot;  &quot;KADDR&quot;,
                        &quot;X$KTATL&quot;.&quot;KSQLKSES&quot;  &quot;SADDR&quot;,
                        &quot;X$KTATL&quot;.&quot;KSQLKRES&quot;  &quot;RADDR&quot;,
                        &quot;X$KTATL&quot;.&quot;KSQLKMOD&quot;  &quot;LMODE&quot;,
                        &quot;X$KTATL&quot;.&quot;KSQLKREQ&quot;  &quot;REQUEST&quot;,
                        &quot;X$KTATL&quot;.&quot;KSQLKCTIM&quot; &quot;CTIME&quot;,
                        &quot;X$KTATL&quot;.&quot;KSQLKLBLK&quot; &quot;BLOCK&quot;
                   FROM SYS.&quot;X$KTATL&quot; &quot;X$KTATL&quot;
                  WHERE BITAND(&quot;X$KTATL&quot;.&quot;KSSOBFLG&quot;, 1) &lt;&gt; 0
                    AND (&quot;X$KTATL&quot;.&quot;KSQLKMOD&quot; &lt;&gt; 0 OR
                         &quot;X$KTATL&quot;.&quot;KSQLKREQ&quot; &lt;&gt; 0)) 
                UNION ALL
                (SELECT &quot;X$KTSTUSC&quot;.&quot;INST_ID&quot;   &quot;INST_ID&quot;,
                        &quot;X$KTSTUSC&quot;.&quot;ADDR&quot;      &quot;LADDR&quot;,
                        &quot;X$KTSTUSC&quot;.&quot;KSQLKADR&quot;  &quot;KADDR&quot;,
                        &quot;X$KTSTUSC&quot;.&quot;KSQLKSES&quot;  &quot;SADDR&quot;,
                        &quot;X$KTSTUSC&quot;.&quot;KSQLKRES&quot;  &quot;RADDR&quot;,
                        &quot;X$KTSTUSC&quot;.&quot;KSQLKMOD&quot;  &quot;LMODE&quot;,
                        &quot;X$KTSTUSC&quot;.&quot;KSQLKREQ&quot;  &quot;REQUEST&quot;,
                        &quot;X$KTSTUSC&quot;.&quot;KSQLKCTIM&quot; &quot;CTIME&quot;,
                        &quot;X$KTSTUSC&quot;.&quot;KSQLKLBLK&quot; &quot;BLOCK&quot;
                   FROM SYS.&quot;X$KTSTUSC&quot; &quot;X$KTSTUSC&quot;
                  WHERE BITAND(&quot;X$KTSTUSC&quot;.&quot;KSSOBFLG&quot;, 1) &lt;&gt; 0
                    AND (&quot;X$KTSTUSC&quot;.&quot;KSQLKMOD&quot; &lt;&gt; 0 OR
                         &quot;X$KTSTUSC&quot;.&quot;KSQLKREQ&quot; &lt;&gt; 0)) 
                UNION ALL
                (SELECT &quot;X$KTSTUSS&quot;.&quot;INST_ID&quot;   &quot;INST_ID&quot;,
                        &quot;X$KTSTUSS&quot;.&quot;ADDR&quot;      &quot;LADDR&quot;,
                        &quot;X$KTSTUSS&quot;.&quot;KSQLKADR&quot;  &quot;KADDR&quot;,
                        &quot;X$KTSTUSS&quot;.&quot;KSQLKSES&quot;  &quot;SADDR&quot;,
                        &quot;X$KTSTUSS&quot;.&quot;KSQLKRES&quot;  &quot;RADDR&quot;,
                        &quot;X$KTSTUSS&quot;.&quot;KSQLKMOD&quot;  &quot;LMODE&quot;,
                        &quot;X$KTSTUSS&quot;.&quot;KSQLKREQ&quot;  &quot;REQUEST&quot;,
                        &quot;X$KTSTUSS&quot;.&quot;KSQLKCTIM&quot; &quot;CTIME&quot;,
                        &quot;X$KTSTUSS&quot;.&quot;KSQLKLBLK&quot; &quot;BLOCK&quot;
                   FROM SYS.&quot;X$KTSTUSS&quot; &quot;X$KTSTUSS&quot;
                  WHERE BITAND(&quot;X$KTSTUSS&quot;.&quot;KSSOBFLG&quot;, 1) &lt;&gt; 0
                    AND (&quot;X$KTSTUSS&quot;.&quot;KSQLKMOD&quot; &lt;&gt; 0 OR
                         &quot;X$KTSTUSS&quot;.&quot;KSQLKREQ&quot; &lt;&gt; 0)) 
                UNION ALL
                (SELECT &quot;X$KTSTUSG&quot;.&quot;INST_ID&quot;   &quot;INST_ID&quot;,
                        &quot;X$KTSTUSG&quot;.&quot;ADDR&quot;      &quot;LADDR&quot;,
                        &quot;X$KTSTUSG&quot;.&quot;KSQLKADR&quot;  &quot;KADDR&quot;,
                        &quot;X$KTSTUSG&quot;.&quot;KSQLKSES&quot;  &quot;SADDR&quot;,
                        &quot;X$KTSTUSG&quot;.&quot;KSQLKRES&quot;  &quot;RADDR&quot;,
                        &quot;X$KTSTUSG&quot;.&quot;KSQLKMOD&quot;  &quot;LMODE&quot;,
                        &quot;X$KTSTUSG&quot;.&quot;KSQLKREQ&quot;  &quot;REQUEST&quot;,
                        &quot;X$KTSTUSG&quot;.&quot;KSQLKCTIM&quot; &quot;CTIME&quot;,
                        &quot;X$KTSTUSG&quot;.&quot;KSQLKLBLK&quot; &quot;BLOCK&quot;
                   FROM SYS.&quot;X$KTSTUSG&quot; &quot;X$KTSTUSG&quot;
                  WHERE BITAND(&quot;X$KTSTUSG&quot;.&quot;KSSOBFLG&quot;, 1) &lt;&gt; 0
                    AND (&quot;X$KTSTUSG&quot;.&quot;KSQLKMOD&quot; &lt;&gt; 0 OR
                         &quot;X$KTSTUSG&quot;.&quot;KSQLKREQ&quot; &lt;&gt; 0)) 
                UNION ALL
                (SELECT &quot;X$KTCXB&quot;.&quot;INST_ID&quot;   &quot;INST_ID&quot;,
                        &quot;X$KTCXB&quot;.&quot;KTCXBXBA&quot;  &quot;LADDR&quot;,
                        &quot;X$KTCXB&quot;.&quot;KTCXBLKP&quot;  &quot;KADDR&quot;,
                        &quot;X$KTCXB&quot;.&quot;KSQLKSES&quot;  &quot;SADDR&quot;,
                        &quot;X$KTCXB&quot;.&quot;KSQLKRES&quot;  &quot;RADDR&quot;,
                        &quot;X$KTCXB&quot;.&quot;KSQLKMOD&quot;  &quot;LMODE&quot;,
                        &quot;X$KTCXB&quot;.&quot;KSQLKREQ&quot;  &quot;REQUEST&quot;,
                        &quot;X$KTCXB&quot;.&quot;KSQLKCTIM&quot; &quot;CTIME&quot;,
                        &quot;X$KTCXB&quot;.&quot;KSQLKLBLK&quot; &quot;BLOCK&quot;
                   FROM SYS.&quot;X$KTCXB&quot; &quot;X$KTCXB&quot;
                  WHERE BITAND(&quot;X$KTCXB&quot;.&quot;KSSPAFLG&quot;, 1) &lt;&gt; 0
                    AND (&quot;X$KTCXB&quot;.&quot;KSQLKMOD&quot; &lt;&gt; 0 OR
                         &quot;X$KTCXB&quot;.&quot;KSQLKREQ&quot; &lt;&gt; 0))) &quot;GV$_LOCK&quot;
         WHERE &quot;GV$_LOCK&quot;.&quot;INST_ID&quot; = USERENV(&#39;INSTANCE&#39;)
      ) &quot;L&quot;,
       SYS.&quot;X$KSUSE&quot; &quot;S&quot;,
       SYS.&quot;X$KSQRS&quot; &quot;R&quot;
 WHERE &quot;L&quot;.&quot;SADDR&quot; = &quot;S&quot;.&quot;ADDR&quot;
   AND &quot;L&quot;.&quot;RADDR&quot; = &quot;R&quot;.&quot;ADDR&quot;
&lt;/pre&gt;&lt;/div&gt;Но попытавшись начать форматировать после обработки бьютифаером, я бросил это дело поленившись и решил разобрать поступательно через v$fixed_view_definition. Так получилось гораздо лучше:&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;10.2.0.4-11.2.0.1&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;/-------------------------- V$LOCK
select  ADDR , KADDR , SID , TYPE , ID1 , ID2 , LMODE , REQUEST , CTIME , BLOCK 
from GV$LOCK 
where inst_id = USERENV(&#39;Instance&#39;)
/-------------------------- GV$LOCK
select s.inst_id                             INST_ID
      ,l.laddr                               ADDR   
      ,l.kaddr                               KADDR
      ,s.ksusenum                            SID
      ,r.ksqrsidt                            TYPE
      ,r.ksqrsid1                            ID1
      ,r.ksqrsid2                            ID2
      ,l.lmode                               LMODE
      ,l.request                             REQUEST
      ,l.ctime                               CTIME
      ,decode(l.lmode, 0, 0, l.block)        BLOCK
from v$_lock l, x$ksuse s, x$ksqrs r 
where l.saddr=s.addr and l.raddr=r.addr
/--------------------      V$_LOCK  -----------------------------------------
select  LADDR , KADDR , SADDR , RADDR , LMODE , REQUEST , CTIME , BLOCK 
from GV$_LOCK 
where inst_id = USERENV(&#39;Instance&#39;)
/--------------------      GV$_LOCK  -----------------------------------------
select USERENV(&#39;Instance&#39;) inst_id,laddr,kaddr,saddr,raddr,lmode,request,ctime,  block 
from v$_lock1 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktadm /**** 1 *****/
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktatrfil 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktatrfsl 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktatl 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktstusc 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktstuss 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktstusg 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,ktcxbxba,ktcxblkp,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktcxb 
where bitand(ksspaflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0)
/------------------ V$_LOCK1
select  LADDR , KADDR , SADDR , RADDR , LMODE , REQUEST , CTIME , BLOCK 
from GV$_LOCK1 
where inst_id = USERENV(&#39;Instance&#39;)
/------------------ GV$_LOCK1
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim, ksqlklblk 
from x$kdnssf 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim, ksqlklblk 
from x$ksqeq 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0)
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;spoiler&quot; title=&quot;11.2.0.3&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;/-------------------------- V$LOCK
select  ADDR , KADDR , SID , TYPE , ID1 , ID2 , LMODE , REQUEST , CTIME , BLOCK 
from GV$LOCK 
where inst_id = USERENV(&#39;Instance&#39;)
/-------------------------- GV$LOCK
select s.inst_id                             INST_ID  
      ,l.laddr                               ADDR    
      ,l.kaddr                               KADDR
      ,s.ksusenum                            SID
      ,r.ksqrsidt                            TYPE
      ,r.ksqrsid1                            ID1
      ,r.ksqrsid2                            ID2
      ,l.lmode                               LMODE
      ,l.request                             REQUEST                      
      ,l.ctime                               CTIME
      ,decode(l.lmode, 0, 0, l.block)        BLOCK
from v$_lock l, x$ksuse s, x$ksqrs r  
where l.saddr=s.addr and concat(USERENV(&#39;Instance&#39;),l.raddr)=concat(r.inst_id,r.addr)
/--------------------      V$_LOCK  -----------------------------------------
select  LADDR , KADDR , SADDR , RADDR , LMODE , REQUEST , CTIME , BLOCK 
from GV$_LOCK 
where inst_id = USERENV(&#39;Instance&#39;)
/--------------------      GV$_LOCK  -----------------------------------------
select USERENV(&#39;Instance&#39;) inst_id,laddr,kaddr,saddr,raddr,lmode,request,ctime,  block 
from v$_lock1 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktadm 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktatrfil 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktatrfsl 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktatl 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktstusc 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktstuss 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktstusg 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,ktcxbxba,ktcxblkp,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
from x$ktcxb 
where bitand(ksspaflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0)  
/------------------ V$_LOCK1
select  LADDR , KADDR , SADDR , RADDR , LMODE , REQUEST , CTIME , BLOCK 
from GV$_LOCK1 
where inst_id = USERENV(&#39;Instance&#39;)
/------------------ GV$_LOCK1
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim, ksqlklblk 
from x$kdnssf 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
    union all 
select inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim, ksqlklblk 
from x$ksqeq 
where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0)        
&lt;/pre&gt;&lt;/div&gt;Кстати, как можно заметить есть разница в gv$lock между версиями и ее нужно учесть(на 11.2.0.2 я еще не смотрел - позже подправлю): &lt;br /&gt;
в 11.2.0.3 предикат l.raddr=r.addr изменился на concat(USERENV(&#39;Instance&#39;),l.raddr)=concat(r.inst_id,r.addr).&lt;br /&gt;
В моей ситуации из v$lock запрашивались только конкретные блокировки, причем основными из них были пользовательские, т.е. с типом &#39;UL&#39; - user locks. Поэтому разобрав код, нужно было получить какие блокировки возвращает каждый конкретный блок union all. Для этого я создал модифицированный GV$LOCK:&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;xt_gv$_lock для 11.2.0.3&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;create or replace view xt_gv$_lock as
with XT_GV$_LOCK as (
      select 1 sq
             ,USERENV(&#39;Instance&#39;) inst_id,laddr,kaddr,saddr,raddr,lmode,request,ctime,  block 
      from v$_lock1 
          union all 
      select 2
             ,inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
      from x$ktadm 
      where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
          union all 
      select 3
             ,inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
      from x$ktatrfil 
      where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
          union all 
      select 4
             ,inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
      from x$ktatrfsl 
      where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
          union all 
      select 5
             ,inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
      from x$ktatl 
      where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
          union all 
      select 6
             ,inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
      from x$ktstusc 
      where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
          union all 
      select 7
             ,inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
      from x$ktstuss 
      where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
          union all 
      select 8
             ,inst_id,addr,ksqlkadr,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
      from x$ktstusg 
      where bitand(kssobflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0) 
          union all 
      select 9
             ,inst_id,ktcxbxba,ktcxblkp,ksqlkses,ksqlkres,ksqlkmod,ksqlkreq, ksqlkctim,ksqlklblk 
      from x$ktcxb 
      where bitand(ksspaflg,1)!=0 and (ksqlkmod!=0 or ksqlkreq!=0)
)
select l.sq 
      ,s.inst_id                             INST_ID  
      ,l.laddr                               ADDR    
      ,l.kaddr                               KADDR
      ,s.ksusenum                            SID
      ,r.ksqrsidt                            TYPE
      ,r.ksqrsid1                            ID1
      ,r.ksqrsid2                            ID2
      ,l.lmode                               LMODE
      ,l.request                             REQUEST                      
      ,l.ctime                               CTIME
      ,decode(l.lmode,0,0,l.block)           BLOCK
from XT_GV$_LOCK l, x$ksuse s, x$ksqrs r  
where l.saddr=s.addr and concat(USERENV(&#39;Instance&#39;),l.raddr)=concat(r.inst_id,r.addr)
/
create or replace public synonym xt_gv$lock for xt_gv$_lock
/
grant select on xt_gv$lock to public
/
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
Теперь можем получить на нагруженной базе соответствие типов блокировок ~ конкретному блоку:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;with t as (select distinct sq,type from xt_gv$lock l)
select sq
      ,listagg(t.TYPE,&#39;,&#39;) within group(order by t.type)
from t
group by sq
&lt;/pre&gt;Где sq - это номер блока union all.&lt;br /&gt;
Или просто получить номер блока фильтром по нужному типу блокировки. Так, например, &#39;UL&#39; будут в первом блоке и теперь, чтобы без проблем их выбирать можно запрашивать из этой новой вьюхи с добавлением предиката sq=1, чтобы не мучать зря другие блоки. &lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select * 
from xt_gv$lock l
where l.type=&#39;UL&#39; 
and l.sq=1 -- первый блок, где ul и бывают
&lt;/pre&gt;В моем нагрузочном тесте в условиях конкуренции модифицированный запрос по user locks не только полностью решил проблему с латчами, да еще и приблизительно в 200 раз ускорил выполнение запроса и существенно снял нагрузку с cpu.&lt;br /&gt;
&lt;br /&gt;
Файлы скриптов:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Для 10.2 - 11.2.0.1: &lt;a href=&quot;/sql/vlock/xt_gv_lock_11_2_0_1.sql&quot; target=&quot;_blank&quot;&gt;xt_gv$_lock_11_2_0_1.sql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Для 11.2.0.3: &lt;a href=&quot;/sql/vlock/xt_gv_lock_11_2_0_3.sql&quot; target=&quot;_blank&quot;&gt;xt_gv$_lock_11_2_0_3.sql&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/7907757324411762410/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/06/latch-free-dml-allocation-latch-vlock.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/7907757324411762410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/7907757324411762410'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/06/latch-free-dml-allocation-latch-vlock.html' title='Большое количество latch free: dml allocation latch при конкурентных запросах к v$lock'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-6988521090004930606</id><published>2012-06-27T02:42:00.002+03:00</published><updated>2012-11-14T00:04:51.291+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="hint"/><category scheme="http://www.blogger.com/atom/ns#" term="hints"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle 11.2"/><category scheme="http://www.blogger.com/atom/ns#" term="undocumented hints"/><category scheme="http://www.blogger.com/atom/ns#" term="недокументированные"/><category scheme="http://www.blogger.com/atom/ns#" term="хинты"/><title type='text'>Список и описание новых хинтов в Oracle 11.1 - 11.2.0.3(включая недокументированные)</title><content type='html'>Увидев новые пару строк на 11.2.0.3 в списке хинтов(V$SQL_HINT), решил свести их описания в одну удобную заметку, попутно попытавшись разобраться в них. &lt;br /&gt;
Описание до конца еще не закончено, постараюсь сделать это на днях.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Cписок хинтов добавленных в 11g&lt;/b&gt;&lt;!-- &gt;&lt;/b&gt;Cписок&gt; и 10.2.0.5(описания ниже)--&gt;&lt;br /&gt;
&lt;table BORDER=&quot;1&quot;&gt;&lt;tr&gt;&lt;th&gt;NAME&lt;/TH&gt;&lt;th&gt;INVERSE&lt;/TH&gt;&lt;th&gt;VERSION&lt;/TH&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#FULL_OUTER_JOIN_TO_OUTER&quot;&gt;FULL_OUTER_JOIN_TO_OUTER&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_FULL_OUTER_JOIN_TO_OUTER&lt;/TD&gt;&lt;td&gt;11.2.0.3&lt;/TD&gt; &lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#OUTER_JOIN_TO_ANTI&quot;&gt;OUTER_JOIN_TO_ANTI&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_OUTER_JOIN_TO_ANTI&lt;/TD&gt;&lt;td&gt;11.2.0.3&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#TABLE_LOOKUP_BY_NL&quot;&gt;TABLE_LOOKUP_BY_NL&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_TABLE_LOOKUP_BY_NL&lt;/TD&gt;&lt;td&gt;11.2.0.2&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#USE_HASH_GBY_FOR_PUSHDOWN&quot;&gt;USE_HASH_GBY_FOR_PUSHDOWN&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_USE_HASH_GBY_FOR_PUSHDOWN&lt;/TD&gt;&lt;td&gt;11.2.0.2&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#XDB_FASTPATH_INSERT&quot;&gt;XDB_FASTPATH_INSERT&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_XDB_FASTPATH_INSERT&lt;/TD&gt;&lt;td&gt;11.2.0.2&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#APPEND_VALUES&quot;&gt;APPEND_VALUES&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NOAPPEND&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#COALESCE_SQ&quot;&gt;COALESCE_SQ&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_COALESCE_SQ&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#CONNECT_BY_ELIM_DUPS&quot;&gt;CONNECT_BY_ELIM_DUPS&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_CONNECT_BY_ELIM_DUPS&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#DST_UPGRADE_INSERT_CONV&quot;&gt;DST_UPGRADE_INSERT_CONV&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_DST_UPGRADE_INSERT_CONV&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#EXPAND_TABLE&quot;&gt;EXPAND_TABLE&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_EXPAND_TABLE&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#FACTORIZE_JOIN&quot;&gt;FACTORIZE_JOIN&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_FACTORIZE_JOIN&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#NO_SUBSTRB_PAD&quot;&gt;NO_SUBSTRB_PAD&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#PLACE_DISTINCT&quot;&gt;PLACE_DISTINCT&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_PLACE_DISTINCT&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;http://books.google.ru/books?id=1Aqw6mrxz5AC&amp;lpg=PA160&amp;ots=T9sGosYLuH&amp;dq=%22STATEMENT_QUEUING%22&amp;hl=ru&amp;pg=PA160#v=onepage&amp;q=%22STATEMENT_QUEUING%22&amp;f=false&quot;&gt;STATEMENT_QUEUING&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_STATEMENT_QUEUING&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#TRANSFORM_DISTINCT_AGG&quot;&gt;TRANSFORM_DISTINCT_AGG&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_TRANSFORM_DISTINCT_AGG&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;XMLINDEX_SEL_IDX_TBL&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.2.0.1&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#BIND_AWARE&quot;&gt;BIND_AWARE&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_BIND_AWARE&lt;/TD&gt;&lt;td&gt;11.1.0.7&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements006.htm#CHDIFFJE&quot;&gt;CHANGE_DUPKEY_ERROR_INDEX&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.1.0.7&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements006.htm#autoId17&quot;&gt;IGNORE_ROW_ON_DUPKEY_INDEX&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.1.0.7&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;http://docs.oracle.com/cd/E11882_01/server.112/e26088/sql_elements006.htm#autoId71&quot;&gt;RETRY_ON_ROW_CHANGE&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.1.0.7&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;CHECK_ACL_REWRITE&lt;/TD&gt;&lt;td&gt;NO_CHECK_ACL_REWRITE&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;COST_XML_QUERY_REWRITE&lt;/TD&gt;&lt;td&gt;NO_COST_XML_QUERY_REWRITE&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;DB_VERSION&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;DOMAIN_INDEX_FILTER&lt;/TD&gt;&lt;td&gt;NO_DOMAIN_INDEX_FILTER&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;INDEX_RS_ASC&quot;&gt;INDEX_RS_ASC&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;INDEX_RS_ASC&quot;&gt;INDEX_RS_DESC&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements006.htm#autoId27&quot;&gt;MONITOR&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_MONITOR&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;NLJ_BATCHING&quot;&gt;NLJ_BATCHING&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_NLJ_BATCHING&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;NLJ_PREFETCH&quot;&gt;NLJ_PREFETCH&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_NLJ_PREFETCH&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;NO_LOAD&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;OUTER_JOIN_TO_INNER&lt;/TD&gt;&lt;td&gt;NO_OUTER_JOIN_TO_INNER&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;#PLACE_GROUP_BY&quot;&gt;PLACE_GROUP_BY&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_PLACE_GROUP_BY&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements006.htm#BABIFIGC&quot;&gt;RESULT_CACHE&lt;/a&gt;&lt;/TD&gt;&lt;td&gt;NO_RESULT_CACHE&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;SUBQUERY_PRUNING&lt;/TD&gt;&lt;td&gt;NO_SUBQUERY_PRUNING&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;USE_INVISIBLE_INDEXES&lt;/TD&gt;&lt;td&gt;NO_USE_INVISIBLE_INDEXES&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;USE_MERGE_CARTESIAN&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;XML_DML_RWT_STMT&lt;/TD&gt;&lt;td&gt;&amp;nbsp;&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;XMLINDEX_REWRITE&lt;/TD&gt;&lt;td&gt;NO_XMLINDEX_REWRITE&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;XMLINDEX_REWRITE_IN_SELECT&lt;/TD&gt;&lt;td&gt;NO_XMLINDEX_REWRITE_IN_SELECT&lt;/TD&gt;&lt;td&gt;11.1.0.6&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;CONNECT_BY_CB_WHR_ONLY&lt;/TD&gt;&lt;td&gt;NO_CONNECT_BY_CB_WHR_ONLY&lt;/TD&gt;&lt;td&gt;10.2.0.5&lt;/TD&gt;&lt;/TR&gt;
&lt;!--
&lt;tr&gt;&lt;td&gt;GBY_PUSHDOWN&lt;/TD&gt;&lt;td&gt;NO_GBY_PUSHDOWN&lt;/TD&gt;&lt;td&gt;10.2.0.5&lt;/TD&gt;&lt;/TR&gt;
--&gt; &lt;/TABLE&gt;&lt;a name=&quot;FULL_OUTER_JOIN_TO_OUTER&quot;&gt;&lt;h3&gt;FULL_OUTER_JOIN_TO_OUTER / NO_FULL_OUTER_JOIN_TO_OUTER&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_CBO&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;FULL_OUTER_JOIN_TO_OUTER&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Включает/выключает механизм трансформации запроса из full outer join в left outer join, появившийся и работающий по умолчанию с 11.2.0.2. &lt;br /&gt;
Помимо самого хинта, появившегося в 11.2.0.3, управлять этим преобразованием можно начиная с 11.2.0.2 через fix control (bugno=9287401) и с помощью:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;OPT_PARAM(&#39;_optimizer_full_outer_join_to_outer&#39; &#39;false&#39;)&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
или &lt;i&gt;alter session set &quot;_optimizer_full_outer_join_to_outer&quot;=true;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;p /&gt;Пример:&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Тестовые таблицы:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;create table mss_foj1(id primary key, a, constraint uq_foj1_a unique(a) using index) as select level id, level*2-1 a from dual connect by level&lt;=1e5;
create table mss_foj2(id primary key, a, constraint uq_foj2_a unique(a) using index) as select level id, level*2 a from dual connect by level&lt;=1e5;
begin
   dbms_stats.gather_table_stats(user,&#39;mss_foj1&#39;,cascade=&gt;true);
   dbms_stats.gather_table_stats(user,&#39;mss_foj2&#39;,cascade=&gt;true);
end;
/
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Пример трансформированного:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;&gt;&gt; explain plan for
  2  select
  3   *
  4  from mss_foj1 f1
  5       full outer join mss_foj2 f2
  6                  on f1.id=f2.id
  7  where f1.a=3;

Explained.

Elapsed: 00:00:00.03
 &gt;&gt; @xplan

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------

Plan hash value: 2311935082

---------------------------------------------------------------------------------------------
| Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |              |     1 |    20 |     2   (0)| 00:00:01 |
|   1 |  NESTED LOOPS OUTER          |              |     1 |    20 |     2   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| MSS_FOJ1     |     1 |    10 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | UQ_FOJ1_A    |     1 |       |     1   (0)| 00:00:01 |
|   4 |   TABLE ACCESS BY INDEX ROWID| MSS_FOJ2     |   100K|   976K|     1   (0)| 00:00:01 |
|*  5 |    INDEX UNIQUE SCAN         | SYS_C0094323 |     1 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access(&quot;F1&quot;.&quot;A&quot;=3)
   5 - access(&quot;F1&quot;.&quot;ID&quot;=&quot;F2&quot;.&quot;ID&quot;(+))

18 rows selected.

Elapsed: 00:00:00.18
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Нетрансформированного:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;&gt;&gt; alter session set &quot;_optimizer_full_outer_join_to_outer&quot;=false;

Session altered.

Elapsed: 00:00:00.01
 &gt;&gt; explain plan for
  2  select
  3   *
  4  from mss_foj1 f1
  5       full outer join mss_foj2 f2
  6                  on f1.id=f2.id
  7  where f1.a=3;

Explained.

Elapsed: 00:00:00.04
 &gt;&gt; @xplan

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------

Plan hash value: 2034556344

------------------------------------------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |   100K|  5078K|       |  1684  (14)| 00:00:01 |
|*  1 |  VIEW                 | VW_FOJ_0 |   100K|  5078K|       |  1684  (14)| 00:00:01 |
|*  2 |   HASH JOIN FULL OUTER|          |   100K|  1953K|  2152K|  1684  (14)| 00:00:01 |
|   3 |    TABLE ACCESS FULL  | MSS_FOJ1 |   100K|   976K|       |   269  (22)| 00:00:01 |
|   4 |    TABLE ACCESS FULL  | MSS_FOJ2 |   100K|   976K|       |   268  (22)| 00:00:01 |
------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(&quot;F1&quot;.&quot;A&quot;=3)
   2 - access(&quot;F1&quot;.&quot;ID&quot;=&quot;F2&quot;.&quot;ID&quot;)

17 rows selected.

Elapsed: 00:00:01.03
&lt;/pre&gt;&lt;/div&gt;&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;OUTER_JOIN_TO_ANTI&quot;&gt;&lt;h3&gt;OUTER_JOIN_TO_ANTI / NO_OUTER_JOIN_TO_ANTI&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_CBO&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;OUTER_JOIN_TO_ANTI&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Судя по названию и скрытому параметру _optimizer_outer_to_anti_enabled (Enable transformation of outer-join to anti-join if possible), введенному еще в 10.2, этот хинт отвечает за трансформацию outer join&#39;ов к anti-join, но мне, к сожалению, не удалось воспроизвести это, и буду рад, если кто-нибудь поделится примером. Скажу сразу, что я пробовал только простые запросы полные аналоги классического anti-join&#39;a.&lt;br /&gt;
&lt;!-- --------------------------------------------------- 
     --------------   11.2.0.2  ------------------------
     --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;TABLE_LOOKUP_BY_NL&quot;&gt;&lt;h3&gt;TABLE_LOOKUP_BY_NL / NO_TABLE_LOOKUP_BY_NL&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_TABLE_LOOKUP_BY_NL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;TABLE_LOOKUP_BY_NL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;С этим хинтом у меня тоже, к сожалению, разобраться не получилось. Из описания параметра &quot;_optimizer_enable_table_lookup_by_nl&quot; - consider table lookup by nl transformation. Кстати говоря, этот параметр в 11.2.0.1 по умолчанию был false, а с 11.2.0.2 - true.&lt;br /&gt;
В первую очередь я подумал, что он связан с &lt;a href=&quot;http://docs.oracle.com/cd/E11882_01/server.112/e16638/optimops.htm#sthref955&quot;&gt;новым вариантом nested loops&lt;/a&gt; появившемся в 11g, но у него есть свой хинт - NLJ_BATCHING. Второй мыслью было о том, что хинт отвечает за включение/выключение этапа анализа для возможности NLJ_BATCHING, но добавление хинта в запросы с nested loops планов не меняло(попозже попробую проанализировать трассировку 10053 с ним на различных nl - будет ли видно, что он добавляет/убирает). Третью мыслью было, что это относится к механизму table lookup prefetch, но тоже не получилось их как-то связать, т.к. у того тоже есть свое название - NLJ_PREFETCH.&lt;br /&gt;
&lt;br /&gt;
В общем тоже прощу сообщить, если узнаете за что этот хинт отвечает.&lt;br /&gt;
&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;USE_HASH_GBY_FOR_PUSHDOWN&quot;&gt;&lt;h3&gt;USE_HASH_GBY_FOR_PUSHDOWN / NO_USE_HASH_GBY_FOR_PUSHDOWN&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;USE_HASH_GBY_FOR_PUSHDOWN&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;USE_HASH_GBY_FOR_PUSHDOWN&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;И еще один хинт с которым не получилось разобраться: тоже судя по названию только догадываюсь о том, что этот хинт отвечает за использование hash group by для view pushed predicate, но сделать так, чтобы он хоть что-нибудь менял в 10053 мне не удалось. При этом, если моя догадка верна, непонятно где именно должен быть hash group by - по идее для hash group by задумывался use_hash_aggregation. &lt;br /&gt;
Правда он черезчур загадочный: например, даже при появлении его в плане в секции outline, в самом плане может быть sort group by:&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Пример появления use_hash_aggregation:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;ORCL/XTENDER&gt; explain plan for
  2  with v_push as (
  3       select
  4          t_8k.c100
  5          ,count(*) s
  6       from  t_4k
  7            ,t_8k
  8       where t_4k.col_unique=t_8k.col_unique
  9       group by t_8k.c100
 10  )
 11  select
 12    *
 13  from
 14       t_1k
 15      ,v_push
 16  where t_1k.col_unique=v_push.c100(+)
 17        and t_1k.c3=5;

Explained.

Elapsed: 00:00:00.23
ORCL/XTENDER&gt; @xplan

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------

Plan hash value: 438187520

------------------------------------------------------------------------------------------------
| Id  | Operation                       | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                |              |     3 |    96 |     8   (0)| 00:00:01 |
|   1 |  NESTED LOOPS OUTER             |              |     3 |    96 |     8   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID   | T_1K         |     3 |    51 |     2   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN             | IX_T_1K_C3   |     3 |       |     1   (0)| 00:00:01 |
|   4 |   VIEW PUSHED PREDICATE         |              |     1 |    15 |     2   (0)| 00:00:01 |
|   5 |    SORT GROUP BY                |              |     1 |    11 |     2   (0)| 00:00:01 |
|   6 |     NESTED LOOPS                |              |   100 |  1100 |     2   (0)| 00:00:01 |
|   7 |      TABLE ACCESS BY INDEX ROWID| T_8K         |   100 |   700 |     2   (0)| 00:00:01 |
|*  8 |       INDEX RANGE SCAN          | IX_T_8K_C100 |   100 |       |     1   (0)| 00:00:01 |
|*  9 |      INDEX UNIQUE SCAN          | PK_T_4K      |     1 |     4 |     0   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$2
   2 - SEL$2        / T_1K@SEL$2
   3 - SEL$2        / T_1K@SEL$2
   4 - SEL$9113C594 / V_PUSH@SEL$2
   5 - SEL$9113C594
   7 - SEL$9113C594 / T_8K@SEL$1
   8 - SEL$9113C594 / T_8K@SEL$1
   9 - SEL$9113C594 / T_4K@SEL$1

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      USE_HASH_AGGREGATION(@&quot;SEL$9113C594&quot;)
      USE_NL(@&quot;SEL$9113C594&quot; &quot;T_4K&quot;@&quot;SEL$1&quot;)
      LEADING(@&quot;SEL$9113C594&quot; &quot;T_8K&quot;@&quot;SEL$1&quot; &quot;T_4K&quot;@&quot;SEL$1&quot;)

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------

      INDEX(@&quot;SEL$9113C594&quot; &quot;T_4K&quot;@&quot;SEL$1&quot; (&quot;T_4K&quot;.&quot;COL_UNIQUE&quot;))
      INDEX_RS_ASC(@&quot;SEL$9113C594&quot; &quot;T_8K&quot;@&quot;SEL$1&quot; (&quot;T_8K&quot;.&quot;C100&quot;))
      USE_NL(@&quot;SEL$2&quot; &quot;V_PUSH&quot;@&quot;SEL$2&quot;)
      LEADING(@&quot;SEL$2&quot; &quot;T_1K&quot;@&quot;SEL$2&quot; &quot;V_PUSH&quot;@&quot;SEL$2&quot;)
      NO_ACCESS(@&quot;SEL$2&quot; &quot;V_PUSH&quot;@&quot;SEL$2&quot;)
      INDEX_RS_ASC(@&quot;SEL$2&quot; &quot;T_1K&quot;@&quot;SEL$2&quot; (&quot;T_1K&quot;.&quot;C3&quot;))
      OUTLINE(@&quot;SEL$2&quot;)
      OUTLINE(@&quot;SEL$1&quot;)
      OUTLINE_LEAF(@&quot;SEL$2&quot;)
      PUSH_PRED(@&quot;SEL$2&quot; &quot;V_PUSH&quot;@&quot;SEL$2&quot; 1)
      OUTLINE_LEAF(@&quot;SEL$9113C594&quot;)
      ALL_ROWS
      DB_VERSION(&#39;11.2.0.3&#39;)
      OPTIMIZER_FEATURES_ENABLE(&#39;11.2.0.3&#39;)
      IGNORE_OPTIM_EMBEDDED_HINTS
      END_OUTLINE_DATA
  */

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access(&quot;T_1K&quot;.&quot;C3&quot;=5)
   8 - access(&quot;T_8K&quot;.&quot;C100&quot;=&quot;T_1K&quot;.&quot;COL_UNIQUE&quot;)
   9 - access(&quot;T_4K&quot;.&quot;COL_UNIQUE&quot;=&quot;T_8K&quot;.&quot;COL_UNIQUE&quot;)
&lt;/pre&gt;&lt;/div&gt;&lt;!-- --------------------------------------------------- 
 --------------------------------------------------- 
 --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;XDB_FASTPATH_INSERT&quot;&gt;&lt;h3&gt;XDB_FASTPATH_INSERT / NO_XDB_FASTPATH_INSERT&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_ALL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;XDB_FASTPATH_INSERT&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Не документирован, но имеет свою ошибку:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;ORA-19051: Cannot use fast path insert for this XMLType table

   Cause
   An attempt was made to insert using event 19049 into an XMLType table that does not support fast path insert.

   Action
   Unset event 19049 and try again.
&lt;/pre&gt;&lt;!-- --------------------------------------------------- 
 --------------------------------------------------- 
 ------------------   11.2.0.1  -------------------- 
 --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a name=&quot;APPEND_VALUES&quot;&gt;&lt;h3&gt;APPEND_VALUES / NOAPPEND&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_CBO&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;APPEND_VALUES&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;http://docs.oracle.com/cd/E11882_01/server.112/e17118/sql_elements006.htm#SQLRF51109&quot;&gt;да&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Включает механизм direct path inserts аналогичный insert/*+ append*/ … select, но для insert into … values.&lt;br /&gt;
&lt;p /&gt;Пример:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;forall i in c.first..c.last
insert/*+ APPEND_VALUES*/ values c(i);
&lt;/pre&gt;&lt;br /&gt;
Дополнительно: &lt;a href=&quot;http://www.oracle-base.com/articles/11g/append-values-hint-11gr2.php&quot; title=&quot;Подробный пример&quot;&gt;1&lt;/a&gt;&lt;br /&gt;
&lt;!-- --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;COALESCE_SQ&quot;&gt;&lt;h3&gt;COALESCE_SQ / NO_COALESCE_SQ&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_COALESCE_SQ&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;COALESCE_SQ&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
&lt;p&gt;Включает механизм удаления лишних join&#39;ов c какой-либо таблицей(join elimination) в случаях подзапросов.&lt;/p&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Пример:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;ORCL/XTENDER&gt; explain plan for
  2  select * from mss_foj1 f1
  3  where
  4      exists(select * from mss_foj2 f2 where f2.id=f1.a)
  5  and exists(select * from mss_foj2 f2 where f2.id=f1.a);

Explained.

ORCL/XTENDER&gt; @xplan

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------

Plan hash value: 4138783270

-----------------------------------------------------------------------------------
| Id  | Operation          | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |              | 50000 |   732K|    71  (15)| 00:00:01 |
|   1 |  NESTED LOOPS SEMI |              | 50000 |   732K|    71  (15)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| MSS_FOJ1     |   100K|   976K|    62   (2)| 00:00:01 |
|*  3 |   INDEX UNIQUE SCAN| SYS_C0014388 | 50000 |   244K|     0   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$82F4A621
   2 - SEL$82F4A621 / F1@SEL$1
   3 - SEL$82F4A621 / F2@SEL$2

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      ...
      COALESCE_SQ(@&quot;SEL$2&quot;)
      COALESCE_SQ(@&quot;SEL$3&quot;)
      ...
      END_OUTLINE_DATA
  */

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access(&quot;F2&quot;.&quot;ID&quot;=&quot;F1&quot;.&quot;A&quot;)

ORCL/XTENDER&gt; explain plan for
  2  select/*+ NO_COALESCE_SQ(@SEL$2) NO_UNNEST(@SEL$2) */ * from mss_foj1 f1
  3  where
  4      exists(select * from mss_foj2 f2 where f2.id=f1.a)
  5  and exists(select * from mss_foj2 f2 where f2.id=f1.a)
  6  /

Explained.

Elapsed: 00:00:00.08
ORCL/XTENDER&gt; @xplan

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------

Plan hash value: 2240918256

------------------------------------------------------------------------------------
| Id  | Operation           | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |              |     1 |    15 | 39164   (1)| 00:07:50 |
|*  1 |  FILTER             |              |       |       |            |          |
|   2 |   NESTED LOOPS SEMI |              | 50000 |   732K|    71  (15)| 00:00:01 |
|   3 |    TABLE ACCESS FULL| MSS_FOJ1     |   100K|   976K|    62   (2)| 00:00:01 |
|*  4 |    INDEX UNIQUE SCAN| SYS_C0014388 | 50000 |   244K|     0   (0)| 00:00:01 |
|*  5 |   INDEX UNIQUE SCAN | SYS_C0014388 |     1 |     5 |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter( EXISTS (SELECT /*+ NO_UNNEST NO_COALESCE_SQ */ 0 FROM
              &quot;MSS_FOJ2&quot; &quot;F2&quot; WHERE &quot;F2&quot;.&quot;ID&quot;=:B1))
   4 - access(&quot;F2&quot;.&quot;ID&quot;=&quot;F1&quot;.&quot;A&quot;)
   5 - access(&quot;F2&quot;.&quot;ID&quot;=:B1)

&lt;/pre&gt;&lt;/div&gt;Дополнительно: &lt;br /&gt;
&lt;a href=&quot;http://optimizermagic.blogspot.com/2008/06/why-are-some-of-tables-in-my-query.html&quot; title=&quot;Join elimination: Why are some of the tables in my query missing from the plan?&quot;&gt;1&lt;/a&gt; &lt;a href=&quot;http://timurakhmadeev.wordpress.com/2010/01/18/coalesce_sq/&quot; title=&quot;Подробный пример от Тимура Ахмадеева&quot;&gt;2&lt;/a&gt; &lt;a href=&quot;http://oracle-randolf.blogspot.com/2012/03/coalesce-subquery-transformation.html&quot; title=&quot;Пример от Randolf Geist&quot;&gt;3&lt;/a&gt;&lt;br /&gt;
&lt;!-- --------------------------------------------------- 
     --------------------------------------------------- 
     --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;CONNECT_BY_ELIM_DUPS&quot;&gt;&lt;h3&gt;CONNECT_BY_ELIM_DUPS / NO_CONNECT_BY_ELIM_DUPS&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_ALL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;CONNECT_BY_ELIM_DUPS&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;p&gt;Включает механизм отсева дубликатов в иерархическом запросе(в строке плана с connect by появляется (UNIQUE), например &quot;CONNECT BY NO FILTERING WITH SW (UNIQUE))&quot;, при выключенном просто &quot;CONNECT BY NO FILTERING WITH START-WITH]&quot;.&lt;/p&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Пример:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;select/*+ NO_CONNECT_BY_ELIM_DUPS */ distinct *
from t_connect_by
start with a=1
connect by prior a+1 = a
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;DST_UPGRADE_INSERT_CONV&quot;&gt;&lt;h3&gt;DST_UPGRADE_INSERT_CONV / NO_DST_UPGRADE_INSERT_CONV&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_ALL&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;DST_UPGRADE_INSERT_CONV&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;http://docs.oracle.com/cd/E14072_01/server.112/e10820/initparams077.htm&quot;&gt;отчасти&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Отвечает за работу внутренних операторов с конвертацией столбцов TIMESTAMP WITH TIMEZONE (TSTZ), которые ещё не были обновлены во время перехода на летнее время. &lt;br /&gt;
&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;EXPAND_TABLE&quot;&gt;&lt;h3&gt;EXPAND_TABLE / NO_EXPAND_TABLE&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_TABLE_EXPANSION&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;EXPAND_TABLE&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;В 11gR2 введен новый механизм, позволяющий использовать разные пути доступа к секциям в случаях, когда индексы в некоторых секциях изменены на unusable - это позволяет иметь отключать индексы на нагруженных dml секциях. Механизм хорошо описан &lt;a href=&quot;http://blogs.oracle.com/optimizer/entry/optimizer_transformations_table_expansion&quot;&gt;тут&lt;/a&gt;. За включение механизма отвечает скрытый параметр _optimizer_table_expansion - consider table expansion transformation.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Тестовые данные:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;create table t_expanded(part_key integer, field1 integer, field2 integer, val number)
partition by list(part_key)
(
    partition p1 values(1)
   ,partition p2 values(2)
   ,partition p3 values(3)
   ,partition p4 values(4)
   ,partition p5 values(5)
)
/
create index ix_t_expanded1 on t_expanded(field1, field2) local;
create index ix_t_expanded2 on t_expanded(field2) local;
alter index ix_t_expanded1 modify partition p1 unusable;
alter index ix_t_expanded2 modify partition p2 unusable;
/
insert/*+ APPEND */ into t_expanded
with t as (select level p from dual connect by level&lt;=5)
    ,gen as (select level val from dual connect by level&lt;=1e4)
select t.p
      ,decode(t.p,1,mod(val,3),mod(val,20))
      ,trunc(dbms_random.value(1,1000))
      ,dbms_random.normal
from t
    ,gen
/
select * from t_expanded te where te.field1=:a and te.field2=:b
/
begin 
   dbms_stats.gather_table_stats(null,&#39;t_expanded&#39;,cascade=&gt;true);
end;
/
&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Без expand_table:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;&gt;&gt; explain plan for
  2  select/*+ NO_EXPAND_TABLE(TE) */
  3  *
  4  from t_expanded te
  5  where te.field1=:a
  6    and te.field2=:b;

Explained.

Elapsed: 00:00:00.03
 &gt;&gt; @advanced

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------
Plan hash value: 2740702834

-------------------------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |     3 |    96 |   398  (16)| 00:00:01 |       |       |
|   1 |  PARTITION LIST ALL|            |     3 |    96 |   398  (16)| 00:00:01 |     1 |     5 |
|*  2 |   TABLE ACCESS FULL| T_EXPANDED |     3 |    96 |   398  (16)| 00:00:01 |     1 |     5 |
-------------------------------------------------------------------------------------------------
&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;C expand_table:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;&gt;&gt; explain plan for
  2  select *
  3  from t_expanded te
  4  where te.field1=:a
  5    and te.field2=:b;

Explained.

Elapsed: 00:00:00.04
&gt;&gt; @advanced

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------
Plan hash value: 527277835

-----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name           | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                |     3 |    96 |   242  (15)| 00:00:01 |       |       |
|   1 |  VIEW                                | VW_TE_2        |     6 |   312 |   242  (15)| 00:00:01 |       |       |
|   2 |   UNION-ALL                          |                |       |       |            |          |       |       |
|   3 |    PARTITION LIST INLIST             |                |     2 |    64 |   240  (15)| 00:00:01 |KEY(I) |KEY(I) |
|*  4 |     TABLE ACCESS FULL                | T_EXPANDED     |     2 |    64 |   240  (15)| 00:00:01 |KEY(I) |KEY(I) |
|   5 |    PARTITION LIST SINGLE             |                |     3 |    96 |     1   (0)| 00:00:01 |     1 |     1 |
|*  6 |     TABLE ACCESS BY LOCAL INDEX ROWID| T_EXPANDED     |     3 |    96 |     1   (0)| 00:00:01 |     1 |     1 |
|*  7 |      INDEX RANGE SCAN                | IX_T_EXPANDED2 |    10 |       |     1   (0)| 00:00:01 |     1 |     1 |
|   8 |    PARTITION LIST SINGLE             |                |     1 |    32 |     1   (0)| 00:00:01 |     2 |     2 |
|   9 |     TABLE ACCESS BY LOCAL INDEX ROWID| T_EXPANDED     |     1 |    32 |     1   (0)| 00:00:01 |     2 |     2 |
|* 10 |      INDEX RANGE SCAN                | IX_T_EXPANDED1 |     1 |       |     1   (0)| 00:00:01 |     2 |     2 |
-----------------------------------------------------------------------------------------------------------------------
Outline Data 
-------------
             
  /*+        
      BEGIN_OUTLINE_DATA
      ...
      EXPAND_TABLE(@&quot;SEL$1&quot; &quot;TE&quot;@&quot;SEL$1&quot;)                                                                                                                                 
      ...
      END_OUTLINE_DATA                                                                                                                                                    
  */                                                                                                                                                                      
                                                                                                                                                                          
Predicate Information (identified by operation id):                                                                                                                       
---------------------------------------------------                                                                                                                       
                                                                                                                                                                          
   4 - filter(&quot;TE&quot;.&quot;FIELD2&quot;=TO_NUMBER(:B) AND &quot;TE&quot;.&quot;FIELD1&quot;=TO_NUMBER(:A))                                                                                                
   6 - filter(&quot;TE&quot;.&quot;FIELD1&quot;=TO_NUMBER(:A))                                                                                                                                
   7 - access(&quot;TE&quot;.&quot;FIELD2&quot;=TO_NUMBER(:B))                                                                                                                                
  10 - access(&quot;TE&quot;.&quot;FIELD1&quot;=TO_NUMBER(:A) AND &quot;TE&quot;.&quot;FIELD2&quot;=TO_NUMBER(:B))
&lt;/pre&gt;&lt;/div&gt;&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;FACTORIZE_JOIN&quot;&gt;&lt;h3&gt;FACTORIZE_JOIN / NO_FACTORIZE_JOIN&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_JOINFAC&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;FACTORIZE_JOIN&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;В 11gR2 введен новый механизм, позволяющий объединять обращения к одной присоединяемой таблице по одним и тем же условиям в разных частях &quot;union [all]&quot; в один join на более позднем этапе после слияния других таблиц. Т.е. запрос вида:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select * from t1 join t2 on t1.a=t2.a where предикаты_по_таблице_t1_1
union all
select * from t1 join t2 on t1.a=t2.a where предикаты_по_таблице_t1_2
&lt;/pre&gt;Будет трансформирован в &lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select * 
from t2 
   join (
      select * from t1 where предикаты_по_таблице_t1_1
      union all
      select * from t1 where предикаты_по_таблице_t1_2
   ) on t1.a=t2.a
&lt;/pre&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Пример c FACTORIZE_JOIN:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; explain plan for
  2  select *
  3  from t_1k
  4      ,t_8k
  5  where t_1k.c10=t_8k.c100
  6    and t_1k.col_unique=:a
  7  union all
  8  select *
  9  from t_1k
 10      ,t_8k
 11  where t_1k.c10=t_8k.c100
 12    and t_1k.c1000=:b
 13  /

Explained.

Elapsed: 00:00:00.03
DB11G/XTENDER&gt; @xplan

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------

Plan hash value: 3121763019

-----------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                    |   100K|  9384K|    16   (7)| 00:00:01 |
|*  1 |  HASH JOIN                     |                    |   100K|  9384K|    16   (7)| 00:00:01 |
|   2 |   VIEW                         | VW_JF_SET$154ACCB2 |  1001 | 78078 |     5   (0)| 00:00:01 |
|   3 |    UNION-ALL                   |                    |       |       |            |          |
|   4 |     TABLE ACCESS BY INDEX ROWID| T_1K               |     1 |    17 |     2   (0)| 00:00:01 |
|*  5 |      INDEX UNIQUE SCAN         | PK_T_1K            |     1 |       |     1   (0)| 00:00:01 |
|*  6 |     TABLE ACCESS FULL          | T_1K               |  1000 | 17000 |     3   (0)| 00:00:01 |
|   7 |   TABLE ACCESS FULL            | T_8K               |  8000 |   140K|    10   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      ...
      FACTORIZE_JOIN(@&quot;SET$1&quot;(&quot;T_8K&quot;@&quot;SEL$1&quot; &quot;T_8K&quot;@&quot;SEL$2&quot;))
      ...
      END_OUTLINE_DATA
  */

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access(&quot;ITEM_1&quot;=&quot;T_8K&quot;.&quot;C100&quot;)
   5 - access(&quot;T_1K&quot;.&quot;COL_UNIQUE&quot;=TO_NUMBER(:A))
   6 - filter(&quot;T_1K&quot;.&quot;C1000&quot;=TO_NUMBER(:B))

&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Пример с NO_FACTORIZE_JOIN:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; explain plan for
  2  select--+ NO_FACTORIZE_JOIN(@SET$1)
  3    *
  4  from t_1k
  5      ,t_8k
  6  where t_1k.c10=t_8k.c100
  7    and t_1k.col_unique=:a
  8  union all
  9  select *
 10  from t_1k
 11      ,t_8k
 12  where t_1k.c10=t_8k.c100
 13    and t_1k.c1000=:b;

Explained.

Elapsed: 00:00:00.00
DB11G/XTENDER&gt; @xplan

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------

Plan hash value: 3677413949

----------------------------------------------------------------------------------------------
| Id  | Operation                     | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              | 80100 |  2737K|    18  (78)| 00:00:01 |
|   1 |  UNION-ALL                    |              |       |       |            |          |
|   2 |   NESTED LOOPS                |              |   100 |  3500 |     4   (0)| 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID| T_1K         |     1 |    17 |     2   (0)| 00:00:01 |
|*  4 |     INDEX UNIQUE SCAN         | PK_T_1K      |     1 |       |     1   (0)| 00:00:01 |
|   5 |    TABLE ACCESS BY INDEX ROWID| T_8K         |   100 |  1800 |     2   (0)| 00:00:01 |
|*  6 |     INDEX RANGE SCAN          | IX_T_8K_C100 |   100 |       |     1   (0)| 00:00:01 |
|*  7 |   HASH JOIN                   |              | 80000 |  2734K|    14   (8)| 00:00:01 |
|*  8 |    TABLE ACCESS FULL          | T_1K         |  1000 | 17000 |     3   (0)| 00:00:01 |
|   9 |    TABLE ACCESS FULL          | T_8K         |  8000 |   140K|    10   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SET$1
   2 - SEL$1
   3 - SEL$1 / T_1K@SEL$1
   4 - SEL$1 / T_1K@SEL$1
   5 - SEL$1 / T_8K@SEL$1
   6 - SEL$1 / T_8K@SEL$1
   7 - SEL$2
   8 - SEL$2 / T_1K@SEL$2
   9 - SEL$2 / T_8K@SEL$2

Outline Data
-------------

  /*+
      BEGIN_OUTLINE_DATA
      USE_NL(@&quot;SEL$1&quot; &quot;T_8K&quot;@&quot;SEL$1&quot;)
      LEADING(@&quot;SEL$1&quot; &quot;T_1K&quot;@&quot;SEL$1&quot; &quot;T_8K&quot;@&quot;SEL$1&quot;)
      INDEX_RS_ASC(@&quot;SEL$1&quot; &quot;T_8K&quot;@&quot;SEL$1&quot; (&quot;T_8K&quot;.&quot;C100&quot;))
      INDEX_RS_ASC(@&quot;SEL$1&quot; &quot;T_1K&quot;@&quot;SEL$1&quot; (&quot;T_1K&quot;.&quot;COL_UNIQUE&quot;))
      USE_HASH(@&quot;SEL$2&quot; &quot;T_8K&quot;@&quot;SEL$2&quot;)
      LEADING(@&quot;SEL$2&quot; &quot;T_1K&quot;@&quot;SEL$2&quot; &quot;T_8K&quot;@&quot;SEL$2&quot;)
      FULL(@&quot;SEL$2&quot; &quot;T_8K&quot;@&quot;SEL$2&quot;)
      FULL(@&quot;SEL$2&quot; &quot;T_1K&quot;@&quot;SEL$2&quot;)
      OUTLINE_LEAF(@&quot;SET$1&quot;)
      OUTLINE_LEAF(@&quot;SEL$2&quot;)
      OUTLINE_LEAF(@&quot;SEL$1&quot;)
      ALL_ROWS
      DB_VERSION(&#39;11.2.0.1&#39;)
      OPTIMIZER_FEATURES_ENABLE(&#39;11.2.0.1&#39;)
      IGNORE_OPTIM_EMBEDDED_HINTS
      END_OUTLINE_DATA
  */

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access(&quot;T_1K&quot;.&quot;COL_UNIQUE&quot;=TO_NUMBER(:A))
   6 - access(&quot;T_1K&quot;.&quot;C10&quot;=&quot;T_8K&quot;.&quot;C100&quot;)
   7 - access(&quot;T_1K&quot;.&quot;C10&quot;=&quot;T_8K&quot;.&quot;C100&quot;)
   8 - filter(&quot;T_1K&quot;.&quot;C1000&quot;=TO_NUMBER(:B))
&lt;/pre&gt;&lt;/div&gt;&lt;a href=&quot;http://timurakhmadeev.wordpress.com/2009/12/01/join-factorization/&quot;&gt;Описание и пример от Тимура Ахмадеева&lt;/a&gt;.&lt;br /&gt;
&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;NO_SUBSTRB_PAD&quot;&gt;&lt;h3&gt;NO_SUBSTRB_PAD&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_EXECUTION&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;NO_SUBSTRB_PAD&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Этот хинт используется dbms_stats в запросах сбора гистограмм. Он меняет поведение substrb - с этим хинтом результат substrb после получения подстроки по байтам будет еще обрезан по символам, т.е. остатки от мультибайтовых символов будут убраны:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Пример:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;SQL&gt; select
  2     column_value
  3    ,dump(substrb(column_value,2,8)) &quot;dump 2-8&quot;
  4  from table(sys.odcivarchar2list(&#39;яяяяzz&#39;, &#39;zzzzяя&#39;,&#39;йййййй&#39;));

COLUMN_VAL dump 2-8
---------- --------------------------------------------------
яяяяzz     Typ=1 Len=8: 32,209,143,209,143,209,143,122
zzzzяя     Typ=1 Len=7: 122,122,122,209,143,209,143
йййййй     Typ=1 Len=8: 32,208,185,208,185,208,185,32

3 rows selected.

Elapsed: 00:00:00.00
SQL&gt; select--+ NO_SUBSTRB_PAD
  2     column_value
  3    ,dump(substrb(column_value,2,8)) &quot;dump 2-8&quot;
  4  from table(sys.odcivarchar2list(&#39;яяяяzz&#39;, &#39;zzzzяя&#39;,&#39;йййййй&#39;));

COLUMN_VAL dump 2-8
---------- --------------------------------------------------
яяяяzz     Typ=1 Len=7: 209,143,209,143,209,143,122
zzzzяя     Typ=1 Len=7: 122,122,122,209,143,209,143
йййййй     Typ=1 Len=6: 208,185,208,185,208,185
&lt;/pre&gt;&lt;/div&gt;&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;&lt;br /&gt;
&lt;a name=&quot;PLACE_DISTINCT&quot;&gt;&lt;h3&gt;PLACE_DISTINCT / NO_PLACE_DISTINCT&lt;/h3&gt;&lt;/a&gt;&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_DIST_PLCMT&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;PLACE_DISTINCT&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;В 11.2.0.1 введен новый механизм cbqt - перемещение кляузы distinct в запросах с джойнами с верхнего уровня в inner view, для уменьшения набора данных на наиболее ранних этапах.&lt;br /&gt;
При этом алиасы у этих внутренних представлений в плане будут начинаться с &quot;VW_DTP_&quot;, в примере ниже это VW_DTP_7FEE568E.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Тестовый запрос:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;select
 distinct
  t1.c10,t2.c100
from (
       select c10,c100,c1000
       from t_1k
       where t_1k.col_unique &lt;100
     ) t1
     ,(
       select c10,c100,c1000
       from t_8k
       where t_8k.col_unique in (select t_4k.c10 from t_4k where t_4k.c100=1)
     ) t2
where t1.c10=t2.c10
&lt;/pre&gt;
&lt;/div&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Отрывки из 10053 трассировки для него:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;****************************************
 Cost-Based Group-By/Distinct Placement
****************************************
GBP/DP: Checking validity of GBP/DP for query block SEL$658B16C2 (#1)
GBP: Checking validity of group-by placement for query block SEL$658B16C2 (#1)
GBP: Bypassed: Query has invalid constructs.
DP: Checking validity of distinct placement for query block SEL$658B16C2 (#1)

DP: Using search type: linear
DP: Considering distinct placement on query block SEL$658B16C2 (#1)
****************************************
DP: Starting iteration 1, state space = (2,3) : (0,0)
DP: Original query
******* UNPARSED QUERY IS *******
SELECT DISTINCT &quot;T_1K&quot;.&quot;C10&quot; &quot;C10&quot;,&quot;T_8K&quot;.&quot;C100&quot; &quot;C100&quot; FROM &quot;XTENDER&quot;.&quot;T_4K&quot; &quot;T_4K&quot;,&quot;XTENDER&quot;.&quot;T_1K&quot; &quot;T_1K&quot;,&quot;XTENDER&quot;.&quot;T_8K&quot; &quot;T_8K&quot; WHERE &quot;T_1K&quot;.&quot;C10&quot;=&quot;T_8K&quot;.&quot;C10&quot; AND &quot;T_1K&quot;.&quot;COL_UNIQUE&quot;&lt;100 AND &quot;T_8K&quot;.&quot;COL_UNIQUE&quot;=&quot;T_4K&quot;.&quot;C10&quot; AND &quot;T_4K&quot;.&quot;C100&quot;=1
...
DP: Costing query block.
...
DP: Updated best state, Cost = 17.14
****************************************
DP: Starting iteration 2, state space = (2,3) : (1,0)
DP: Using DP transformation in this iteration.
...
DP: Transformed query
******* UNPARSED QUERY IS *******
SELECT DISTINCT &quot;VW_DTP_7FEE568E&quot;.&quot;ITEM_1&quot; &quot;C10&quot;,&quot;T_8K&quot;.&quot;C100&quot; &quot;C100&quot; FROM  (SELECT DISTINCT &quot;T_1K&quot;.&quot;C10&quot; &quot;ITEM_1&quot; FROM &quot;XTENDER&quot;.&quot;T_1K&quot; &quot;T_1K&quot; WHERE &quot;T_1K&quot;.&quot;COL_UNIQUE&quot;&lt;100) &quot;VW_DTP_7FEE568E&quot;,&quot;XTENDER&quot;.&quot;T_4K&quot; &quot;T_4K&quot;,&quot;XTENDER&quot;.&quot;T_8K&quot; &quot;T_8K&quot; WHERE &quot;VW_DTP_7FEE568E&quot;.&quot;ITEM_1&quot;=&quot;T_8K&quot;.&quot;C10&quot; AND &quot;T_8K&quot;.&quot;COL_UNIQUE&quot;=&quot;T_4K&quot;.&quot;C10&quot; AND &quot;T_4K&quot;.&quot;C100&quot;=1
...
DP: Costing query block.
...
DP: Not update best state, Cost = 18.14
****************************************
DP: Starting iteration 3, state space = (2,3) : (0,1)
DP: Using DP transformation in this iteration.
...
DP: Transformed query
******* UNPARSED QUERY IS *******
SELECT DISTINCT &quot;T_1K&quot;.&quot;C10&quot; &quot;C10&quot;,&quot;T_8K&quot;.&quot;C100&quot; &quot;C100&quot; FROM  (SELECT DISTINCT &quot;T_4K&quot;.&quot;C10&quot; &quot;ITEM_1&quot; FROM &quot;XTENDER&quot;.&quot;T_4K&quot; &quot;T_4K&quot; WHERE &quot;T_4K&quot;.&quot;C100&quot;=1) &quot;VW_DTP_71E93533&quot;,&quot;XTENDER&quot;.&quot;T_1K&quot; &quot;T_1K&quot;,&quot;XTENDER&quot;.&quot;T_8K&quot; &quot;T_8K&quot; WHERE &quot;T_1K&quot;.&quot;C10&quot;=&quot;T_8K&quot;.&quot;C10&quot; AND &quot;T_1K&quot;.&quot;COL_UNIQUE&quot;&lt;100 AND &quot;T_8K&quot;.&quot;COL_UNIQUE&quot;=&quot;VW_DTP_71E93533&quot;.&quot;ITEM_1&quot;
...
DP: Costing query block.
...
DP: Not update best state, Cost = 18.14
****************************************
&lt;/pre&gt;
&lt;/div&gt;&lt;div class=&quot;spoiler&quot; title=&#39;Пример, показывающий что Distinct Placement не работает для &quot;связанных&quot; таблиц(то есть cross-joinы не подойдут)&#39;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;****************************************
 Cost-Based Group-By/Distinct Placement
****************************************
GBP/DP: Checking validity of GBP/DP for query block SEL$5428C7F1 (#1)
DP: Checking validity of distinct placement for query block SEL$5428C7F1 (#1)
DP: Bypassed: Query tables are not connected.
&lt;/pre&gt;&lt;/div&gt;Дополнительно: &lt;a href=&quot;http://timurakhmadeev.wordpress.com/2011/02/28/distinct-placement/&quot;&gt;пример&lt;/a&gt; от Тимура Ахмадеева.
&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;
&lt;a name=&quot;PLACE_GROUP_BY&quot;&gt;&lt;h3&gt;PLACE_GROUP_BY / NO_PLACE_GROUP_BY&lt;/h3&gt;&lt;/a&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_PLACE_GROUP_BY&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;PLACE_GROUP_BY&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.1.0.6&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Этот механизм аналогичен &lt;a href=&quot;#PLACE_DISTINCT&quot;&gt;PLACE_DISTINCT&lt;/a&gt;(точнее, наоборот, т.к. PLACE_DISTINCT появился позже) и уже давно и хорошо описан:
&lt;a href=&quot;http://jonathanlewis.wordpress.com/2008/12/21/group-by/&quot;&gt;У Льюиса&lt;/a&gt;
&lt;a href=&quot;/docs/riyaj_cost_based_query_transformation.pdf&quot;&gt;в презентации Riyaj Shamsudeen&lt;/a&gt;
В планах эти inner-view легко заметить по префиксу &quot;VW_GBC_&quot;, например VW_GBC_10.
&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;
&lt;a name=&quot;TRANSFORM_DISTINCT_AGG&quot;&gt;&lt;h3&gt;TRANSFORM_DISTINCT_AGG / NO_TRANSFORM_DISTINCT_AGG&lt;/h3&gt;&lt;/a&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_INDEX_RS_ASC&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;ACCESS&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.1.0.6&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Тоже новый механизм трансформирования запроса c distinct для использования нового hash group aggregate, у этих вложенных представлений префиксы &quot;VW_DAG_&quot;. Скрытый параметр - &quot;_optimizer_distinct_agg_transform&quot;.
&lt;a href=&quot;http://www.hellodba.com/reader.php?ID=183&amp;lang=en&quot;&gt;Пример&lt;/a&gt;.
&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;
&lt;a name=&quot;BIND_AWARE&quot;&gt;&lt;h3&gt;BIND_AWARE / NO_BIND_AWARE&lt;/h3&gt;&lt;/a&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_CURSOR_SHARING&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;BIND_AWARE&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.1.0.7&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Это известнейший хинт включения/выключения bind aware cursor sharing(is_bind_aware в v$sql_shared_cursor).
&lt;a href=&quot;https://blogs.oracle.com/optimizer/entry/why_are_there_more_cursors_in_11g_for_my_query_containing_bind_variables_1&quot;&gt;Подробнее&lt;/a&gt;
&lt;a href=&quot;http://iusoltsev.wordpress.com/2011/11/14/bind-aware-cursor-sharing-cardinality-feedback-elements/&quot;&gt;Дополнительно&lt;/a&gt;
&lt;a href=&quot;https://blogs.oracle.com/optimizer/entry/how_do_i_force_a&quot;&gt;А тут забавно прочесть, что в официальном блоге рекомендуют недокументированный хинт&lt;/a&gt;

&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;
&lt;a name=&quot;INDEX_RS_ASC&quot;&gt;&lt;h3&gt;INDEX_RS_ASC / INDEX_RS_DESC&lt;/h3&gt;&lt;/a&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_TRANSFORMATION&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;TRANSFORM_DISTINCT_AGG&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.2.0.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Эти обычные хинты для index range scan [asc/desc] появились в общем-то давно, в аутлайнах профилей они в 10.2 уже были.
&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;
&lt;a name=&quot;NLJ_BATCHING&quot;&gt;&lt;h3&gt;NLJ_BATCHING / NO_NLJ_BATCHING&lt;/h3&gt;&lt;/a&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_EXECUTION&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;ACCESS&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.1.0.6&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Как я уже говорил в описании к хинту &lt;a href=&quot;#TABLE_LOOKUP_BY_NL&quot;&gt;TABLE_LOOKUP_BY_NL&lt;/a&gt; в 11g появился &lt;a href=&quot;http://docs.oracle.com/cd/E11882_01/server.112/e16638/optimops.htm#sthref955&quot;&gt;новый вариант nested loops join&lt;/a&gt; и этот NLJ_BATCHING как раз и позволяет включать и выключать этот механизм.

Дополнительно: 
&lt;a href=&quot;http://jeffreylui.wordpress.com/2011/02/21/thoughts-on-nlj_batching/&quot;&gt;Jeff&#39;s blog: Thoughts on NLJ batching&lt;/a&gt;
&lt;a href=&quot;http://dioncho.wordpress.com/2010/08/16/batching-nlj-optimization-and-ordering/&quot;&gt;Dion Cho: Batching NLJ optimization and ordering&lt;/a&gt;
&lt;!-- --------------------------------------------------- 
     ---------------------------------------------------
     --------------------------------------------------- --&gt;
&lt;a name=&quot;NLJ_PREFETCH&quot;&gt;&lt;h3&gt;NLJ_PREFETCH / NO_NLJ_PREFETCH&lt;/h3&gt;&lt;/a&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;SQL feature:&lt;/td&gt;&lt;td&gt;QKSFM_EXECUTION&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Class:&lt;/td&gt;&lt;td&gt;ACCESS&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Version:&lt;/td&gt;&lt;td&gt;11.1.0.6&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Документирован&lt;/td&gt;&lt;td&gt;нет&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Отвечают за механизм nested loops table prefetch, появившийся в 9i, хорошо объяснено тут:
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://oracle-randolf.blogspot.com/2011/07/logical-io-evolution-part-2-9i-10g.html&quot;&gt;Logical I/O - Evolution: Part 2 - 9i, 10g Prefetching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://oracle-randolf.blogspot.com/2011/08/logical-io-evolution-part-3-11g.html&quot;&gt;Logical I/O Evolution - Part 3: 11g&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;и дополнительно &lt;a href=&quot;http://asktom.oracle.com/pls/asktom/f?p=100:11:1591616885374501::::P11_QUESTION_ID:7110065183012&quot;&gt;у Тома&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/6988521090004930606/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/06/oracle-111-11203.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/6988521090004930606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/6988521090004930606'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/06/oracle-111-11203.html' title='Список и описание новых хинтов в Oracle 11.1 - 11.2.0.3(включая недокументированные)'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-378583155449114151</id><published>2012-06-18T22:42:00.000+03:00</published><updated>2012-06-18T22:42:05.464+03:00</updated><title type='text'>В две строки</title><content type='html'>&lt;ol&gt;&lt;li&gt;&lt;a href=&quot;http://carlos-sierra.net/2012/06/05/sqltxplain-sqlt-11-4-4-6-is-now-available/&quot;&gt;Обновился SQLTXPLAIN (SQLT)&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://support.oracle.com/CSP/main/article?cmd=show&amp;type=NOT&amp;id=1366133.1&quot;&gt;Новая версия &quot;SQL Health-Check&quot; скрипта&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/378583155449114151/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/06/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/378583155449114151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/378583155449114151'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/06/blog-post.html' title='В две строки'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-995993448197249818</id><published>2012-06-13T21:08:00.002+03:00</published><updated>2012-06-13T21:25:32.069+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dbms_random"/><category scheme="http://www.blogger.com/atom/ns#" term="parallel"/><title type='text'>dbms_random в параллели</title><content type='html'>В документации к dbms_random &lt;a href=&quot;http://docs.oracle.com/cd/E14072_01/appdev.112/e10577/d_random.htm&quot;&gt;сказано&lt;/a&gt;: &lt;blockquote&gt;It will automatically initialize with the date, user ID, and process ID if no explicit initialization is performed.&lt;/blockquote&gt;Из данной фразы не очевидно, какой &quot;process id&quot; будет использоваться для инициализации в случае параллельного выполнения, поэтому приведу наглядный пример, показывающий независимость генератора dbms_random от &quot;process id&quot; слейва, то есть генерацию одинаковых значений в параллели:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;with
 t  as ( select/*+ materialize */ level n from dual connect by level&lt;=4000)
,t1 as (
         select--+ materialize parallel(t 4)
            dbms_random.string(&#39;x&#39;,4)
            ||&#39;;&#39;
            ||(select sid||&#39;;&#39;||process||&#39;;&#39;||pid
               from v$session, v$process
               where sid=sys_context(&#39;USERENV&#39;,&#39;SID&#39;)
                 and PADDR=ADDR
                 and n&gt;0
              ) f
         from t
)
,t2 as (
         select 
            t1.f
           ,count(*) over(partition by regexp_substr(f,&#39;^[^;]+&#39;)) cnt
         from t1
)
select f
      ,regexp_substr(f,&#39;[^;]+&#39;) rnd
      ,regexp_substr(f,&#39;[^;]+&#39;,1,2) sid
      ,regexp_substr(f,&#39;[^;]+&#39;,1,3) process
      ,regexp_substr(f,&#39;[^;]+&#39;,1,4) pid
from t2 
where cnt&gt;1
order by f
&lt;/pre&gt;&lt;br /&gt;
Результат:&lt;br /&gt;
&lt;table BORDER=&quot;1&quot;&gt;&lt;tr&gt;&lt;th&gt;F&lt;/TH&gt;&lt;th&gt;RND&lt;/TH&gt;&lt;th&gt;SID&lt;/TH&gt;&lt;th&gt;PROCESS&lt;/TH&gt;&lt;th&gt;PID&lt;/TH&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;AARV;130;5472;30&lt;/TD&gt;&lt;td&gt;AARV&lt;/TD&gt;&lt;td&gt;130&lt;/TD&gt;&lt;td&gt;5472&lt;/TD&gt;&lt;td&gt;30&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;AARV;68;2228;29&lt;/TD&gt;&lt;td&gt;AARV&lt;/TD&gt;&lt;td&gt;68&lt;/TD&gt;&lt;td&gt;2228&lt;/TD&gt;&lt;td&gt;29&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;AC2R;130;5472;30&lt;/TD&gt;&lt;td&gt;AC2R&lt;/TD&gt;&lt;td&gt;130&lt;/TD&gt;&lt;td&gt;5472&lt;/TD&gt;&lt;td&gt;30&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;AC2R;68;2228;29&lt;/TD&gt;&lt;td&gt;AC2R&lt;/TD&gt;&lt;td&gt;68&lt;/TD&gt;&lt;td&gt;2228&lt;/TD&gt;&lt;td&gt;29&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;AC8O;130;5472;30&lt;/TD&gt;&lt;td&gt;AC8O&lt;/TD&gt;&lt;td&gt;130&lt;/TD&gt;&lt;td&gt;5472&lt;/TD&gt;&lt;td&gt;30&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;AC8O;68;2228;29&lt;/TD&gt;&lt;td&gt;AC8O&lt;/TD&gt;&lt;td&gt;68&lt;/TD&gt;&lt;td&gt;2228&lt;/TD&gt;&lt;td&gt;29&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;AKVZ;130;5472;30&lt;/TD&gt;&lt;td&gt;AKVZ&lt;/TD&gt;&lt;td&gt;130&lt;/TD&gt;&lt;td&gt;5472&lt;/TD&gt;&lt;td&gt;30&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;AKVZ;68;2228;29&lt;/TD&gt;&lt;td&gt;AKVZ&lt;/TD&gt;&lt;td&gt;68&lt;/TD&gt;&lt;td&gt;2228&lt;/TD&gt;&lt;td&gt;29&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;ALTQ;130;5472;30&lt;/TD&gt;&lt;td&gt;ALTQ&lt;/TD&gt;&lt;td&gt;130&lt;/TD&gt;&lt;td&gt;5472&lt;/TD&gt;&lt;td&gt;30&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;ALTQ;68;2228;29&lt;/TD&gt;&lt;td&gt;ALTQ&lt;/TD&gt;&lt;td&gt;68&lt;/TD&gt;&lt;td&gt;2228&lt;/TD&gt;&lt;td&gt;29&lt;/TD&gt;&lt;/TR&gt;
&lt;tr&gt;&lt;td&gt;...&lt;/TD&gt;&lt;td&gt;...&lt;/TD&gt;&lt;td&gt;...&lt;/TD&gt;&lt;td&gt;...&lt;/TD&gt;&lt;td&gt;...&lt;/TD&gt;&lt;/TR&gt;
&lt;/TABLE&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/995993448197249818/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/06/dbmsrandom.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/995993448197249818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/995993448197249818'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/06/dbmsrandom.html' title='dbms_random в параллели'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-5023310427203169878</id><published>2012-05-18T00:50:00.001+03:00</published><updated>2012-05-18T00:51:54.258+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="exception"/><category scheme="http://www.blogger.com/atom/ns#" term="no_data_found"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><title type='text'>О производительности обработки исключений</title><content type='html'>Эта заметка посвящена известному факту о низкой производительности обработки исключений. &lt;br /&gt;
Да, действительно, обработка исключений достаточно медленна, однако, не стоит сразу же пытаться избегать их везде, где только можно, да еще и любыми способами. Например, часто вижу как их пытаются избегать даже в случаях поиска по первичному ключу c минимальной вероятностью получения no_data_found. &lt;br /&gt;
В целом, стоит учитывать вероятную частоту возникновения исключений и overhead, добавляемый выбранным способом обхода исключений.&lt;br /&gt;
&lt;br /&gt;
Поясню на примере, о котором говорил: пусть есть код, который возвращает поле из таблицы по pk и в случае, если такой записи нет, возвращает null. &lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Тестовая табличка:&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;create table t_test(a primary key, b)
as 
select level,level from dual connect by level&lt;=1e5;
&lt;/pre&gt;
&lt;/div&gt;Создадим эталонную функцию для тестов:
&lt;pre class=&quot;brush: sql&quot;&gt;create or replace function f1(p in number) return number
as
  res number;
begin
  select/*+ F1 */ b into res
  from t_test t
  where t.a=p;
  return res;
exception when no_data_found then
  return null;
end;
&lt;/pre&gt;Как я вижу, наиболее часто в таких случаях пытаются обойти механизм исключений следующими способами:
&lt;div class=&quot;spoiler&quot; title=&quot;Вариант 1&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;create or replace function f2(p in number) return number
as
begin
  for rec in (select/*+ F2 */ b from t_test t where t.a=p) loop
    return rec.b;
  end loop;
  return null;
end;
&lt;/pre&gt;&lt;/div&gt;Кстати, в случаях если у вас в курсоре не может быть больше одной записи, то не делайте так:
&lt;div class=&quot;spoiler&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;create or replace function f2(p in number) return number
as
  res number;
begin
  for rec in (select/*+ F2 */ b from t_test t where t.a=p) loop
    res:=rec.b;
  end loop;
  return res;
end;
&lt;/pre&gt;&lt;/div&gt;Иначе будут попытки второй итерации, что вы сможете увидеть в профайлере.
&lt;div class=&quot;spoiler&quot; title=&quot;Вариант 2&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;create or replace function f3(p in number) return number
as
  res number;
begin
  select/*+ F3 */ min(b) into res
  from t_test t
  where t.a=p;
  return res;
end;
&lt;/pre&gt;&lt;/div&gt;И предложу свой вариант для этого:
&lt;div class=&quot;spoiler&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;create or replace function f4(p in number) return number
as
  res number;
begin
  select/*+ F4 */ 
    (select b from t_test t where t.a=p)
    into res
  from dual;
  return res;
end;
&lt;/pre&gt;&lt;/div&gt;И теперь проведем элементарный тест выполнив эти функции по тестовой табличке:

&lt;pre class=&quot;brush: sql&quot;&gt;declare 
  v       integer;
  v_start integer:= 1;
  v_end   integer:= 100000;
    l_timer integer := dbms_utility.get_time;
    procedure print(msg varchar2) is
    begin
      dbms_output.put_line(to_char((dbms_utility.get_time-l_timer)/100,&#39;9990.00&#39;)||&#39; &#39;||msg);
      l_timer:=dbms_utility.get_time;
    end;
    
begin
  print(&#39;start&#39;);
  for i in v_start..v_end loop
    v:=f1(i);
  end loop;
  print(&#39;1&#39;);
  for i in v_start..v_end loop
    v:=f2(i);
  end loop;
  print(&#39;2&#39;);
  for i in v_start..v_end loop
    v:=f3(i);
  end loop;
  print(&#39;3&#39;);
  for i in v_start..v_end loop
    v:=f4(i);
  end loop;
  print(&#39;4&#39;);
end;
&lt;/pre&gt;В результате мы получим такое соотношение:
&lt;table border=1&gt;&lt;tr&gt;&lt;th&gt;Вариант&lt;/th&gt;&lt;th&gt;Время(c)&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1 вариант(c exception)        &lt;/td&gt;&lt;td&gt;3.03&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2 вариант(c циклом)           &lt;/td&gt;&lt;td&gt;3.62&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3 вариант(c min)              &lt;/td&gt;&lt;td&gt;3.34&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4 вариант(скалярный подзапрос)&lt;/td&gt;&lt;td&gt;3.10&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Как видите, в случае если исключения не вызываются, то оригинальный запрос быстрее всего!
Проверим, теперь с разными процентами исключений: исключения будут для запросов с i&lt;=0, общее кол-во вызовов будет 100001, v_start и v_end буду менять парами: (-5000,95000),(10000,90000),(-50000,50000),(-90000,10000):
&lt;div class=&quot;spoiler&quot;&gt;

&lt;pre class=&quot;brush: sql&quot;&gt;declare 
  v       integer;
  v_start integer:=-50000;
  v_end   integer:= 50000;
    l_timer integer := dbms_utility.get_time;
    procedure print(msg varchar2) is
    begin
      dbms_output.put_line(to_char((dbms_utility.get_time-l_timer)/100,&#39;9990.00&#39;)||&#39; &#39;||msg);
      l_timer:=dbms_utility.get_time;
    end;
    
begin
  print(&#39;start&#39;);
  for i in v_start..v_end loop
    v:=f1(i);
  end loop;
  print(&#39;1&#39;);
  for i in v_start..v_end loop
    v:=f2(i);
  end loop;
  print(&#39;2&#39;);
  for i in v_start..v_end loop
    v:=f3(i);
  end loop;
  print(&#39;3&#39;);
  for i in v_start..v_end loop
    v:=f4(i);
  end loop;
  print(&#39;4&#39;);
end;
&lt;/pre&gt;&lt;/div&gt;Итоговая таблица нескольких сравнений:
&lt;table border=1&gt;&lt;tr&gt;&lt;th&gt;Вариант                       &lt;/th&gt;&lt;th&gt;0%   &lt;/th&gt;&lt;th&gt; ~5% &lt;/th&gt;&lt;th&gt;~10% &lt;/th&gt;&lt;th&gt;~50% &lt;/th&gt;&lt;th&gt;~90% &lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1 вариант(c exception)        &lt;/td&gt;&lt;td&gt;3.04 &lt;/td&gt;&lt;td&gt;3.12 &lt;/td&gt;&lt;td&gt;3.16 &lt;/td&gt;&lt;td&gt;3.82 &lt;/td&gt;&lt;td&gt;4.51 &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2 вариант(c циклом)           &lt;/td&gt;&lt;td&gt;3.18 &lt;/td&gt;&lt;td&gt;3.21 &lt;/td&gt;&lt;td&gt;3.20 &lt;/td&gt;&lt;td&gt;3.51 &lt;/td&gt;&lt;td&gt;3.85 &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3 вариант(c min)              &lt;/td&gt;&lt;td&gt;3.37 &lt;/td&gt;&lt;td&gt;3.34 &lt;/td&gt;&lt;td&gt;3.29 &lt;/td&gt;&lt;td&gt;3.25 &lt;/td&gt;&lt;td&gt;3.18 &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4 вариант(скалярный подзапрос)&lt;/td&gt;&lt;td&gt;3.12 &lt;/td&gt;&lt;td&gt;3.06 &lt;/td&gt;&lt;td&gt;3.03 &lt;/td&gt;&lt;td&gt;2.98 &lt;/td&gt;&lt;td&gt;2.94 &lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;Какие можно сделать выводы:
&lt;ul&gt;&lt;li&gt;Как видите, для &lt;u&gt;данной&lt;/u&gt; таблички 5% исключений - это своего рода переломная точка, когда стандартный вариант с exception начинает проигрывать варианту с подзапросом(если чуть точнее, то это было на ~4.5%), и ~10% другим двум вариантам&lt;/li&gt;
&lt;li&gt;Варианты с min и циклом в целом хуже варианта с подзапросом.&lt;/li&gt;
&lt;li&gt;Варианты с подзапросом и min ускоряются с увеличением количества &quot;пустых&quot; запросов.&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/5023310427203169878/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/05/blog-post.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/5023310427203169878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/5023310427203169878'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/05/blog-post.html' title='О производительности обработки исключений'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-8838691070658492462</id><published>2012-04-28T02:33:00.086+03:00</published><updated>2012-04-29T00:34:04.298+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="collect"/><category scheme="http://www.blogger.com/atom/ns#" term="collection"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="PL/SQL developer"/><category scheme="http://www.blogger.com/atom/ns#" term="типы"/><title type='text'>Забавный факт о collect</title><content type='html'>Многие знают о том, что oracle при необходимости сам создает доменные типы, например, когда используют тип объявленный в пакете(до 11g их можно было увидеть в dba_objects с именем like &#39;PLSQL%&#39;).&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;&lt;b&gt;Факт 1&lt;/b&gt;&lt;/h2&gt;&lt;br /&gt;
Точно так же он поступает и при вызове агрегатной функции &lt;a href=&quot;http://docs.oracle.com/cd/B13789_01/server.101/b10759/functions020.htm&quot;&gt;collect&lt;/a&gt;.&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;-- Сначала проверим есть ли такие типы 
DB11G/XTENDER&gt; select t.type_name,t.type_name,t.typecode 
 2 from dba_types t 
 3 where t.type_name like &#39;SYSTP%&#39;;

no rows selected


-- Выполним запрос с collect
DB11G/XTENDER&gt; select collect(level) from dual connect by level&lt;=10;

COLLECT(LEVEL)
-------------------------------------------------------------------------

SYSTPZvGjVQTySRSjYVlHXyEE2Q==(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

1 row selected.


-- Проверим снова и увидим что появился новый тип SYSTP%
DB11G/XTENDER&gt; select t.type_name,t.type_name,t.typecode 
 2 from dba_types t 
 3 where t.type_name like &#39;SYSTP%&#39;;

TYPE_NAME                      TYPE_NAME                      TYPECODE
------------------------------ ------------------------------ ------------
SYSTPZvGjVQTySRSjYVlHXyEE2Q==  SYSTPZvGjVQTySRSjYVlHXyEE2Q==  COLLECTION
&lt;/pre&gt;И еще выберем данные по нему из sys.obj$ - это нам потом пригодится:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; select obj#,type#,ctime,mtime,stime,status
  2  from sys.obj$ o$
  3  where o$.name = &#39;SYSTPZvGjVQTySRSjYVlHXyEE2Q==&#39;;

  OBJ#  TYPE# CTIME               MTIME               STIME              
------ ------ ------------------- ------------------- -------------------
103600     10 28.04.2012 01:02:35 28.04.2012 01:02:35 28.04.2012 01:02:35
&lt;/pre&gt;Это абсолютно закономерно - нельзя вернуть клиенту информацию не описав ее. &lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;&lt;b&gt;Факт №2&lt;/b&gt;&lt;/h2&gt;Теперь зная, что тип создается, интересно что потом будет с этим типом: будет ли он удален после фетча или после отключения клиента? Например, при удалении пакетного типа автоматически дропался и доменный тип, будет ли здесь аналогичное автоматическое удаление?&lt;br /&gt;
&lt;br /&gt;
Согласно &lt;b&gt;Bug 4033868: COLLECT FUNCTION LEAVES TEMPORARY SYS TYPES BEHIND&lt;/b&gt; этот баг решен в &quot;11.0&quot;, но я тестирую на 11.2.0.1 и элементарная проверка после дисконнекта показала, что тип продолжает существовать до рестарта инстанса, однако на самом деле даже после этого он остается, но в dba_objects уже не выводится.&lt;br /&gt;
&lt;br /&gt;
Я дропну его сам, чтобы лишний раз не рестартить инстанс - это абсолютно аналогично тому как oracle &quot;удаляет&quot; этот тип в 11.2:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; drop type &quot;SYSTPZvGjVQTySRSjYVlHXyEE2Q==&quot;;

Type dropped.
&lt;/pre&gt;А теперь проверим:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; select * from dba_types
   where type_name=&#39;SYSTPZvGjVQTySRSjYVlHXyEE2Q==&#39;;

no rows selected
&lt;/pre&gt;Вроде удалили, однако посмотрим в sys.obj$:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; select obj#,type#,ctime,mtime,stime,status
  2  from sys.obj$ o$
  3  where o$.name = &#39;SYSTPZvGjVQTySRSjYVlHXyEE2Q==&#39;;

  OBJ#  TYPE# CTIME               MTIME               STIME              
------ ------ ------------------- ------------------- -------------------
103600     10 28.04.2012 01:02:35 28.04.2012 01:40:37 31.12.4712 23:59:59
&lt;/pre&gt;Как видите, объект остался, но с type#=10 и с stime равным последней дате 4712 года, а раньше было type#=13 и stime=mtime=ctime, а в 10.2 при ручном дропе этого типа никаких записей не оставалось. Поясню соответствия полей из sys.obj$ и dba_objects, чтобы было понятней: obj# - object_id, type# ~ код типа, ctime,mtime,stime - created, last_ddl_time, timestamp соответственно. По коду представления dba_objects мы увидим, что type# = 10 - это якобы &quot;NON-EXISTENT&quot; и выводить его не нужно.&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;and (o.type# not in (1  /* INDEX - handled below */,
                      10 /* NON-EXISTENT */)
&lt;/pre&gt;А установка даты в 31.12.4712 23:59:59 указывает на его неактуальность - уж слишком далекое будущее :)&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;&lt;b&gt;Факт №3&lt;/b&gt;&lt;/h2&gt;Теперь перейдем к тому, что меня собственно заставило повозиться с collect: ошибки с параллельным выполнением collect (&lt;a href=&quot;http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&amp;tid=937491&amp;msg=12482005&quot;&gt;обсуждение на форуме с указанием и подробным описанием Bug 11906197&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
Вообще collect довольно глючная штука, я и сам на это уже неоднократно &lt;a href=&quot;http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&amp;tid=607879&amp;msg=10137740&quot;&gt;нарывался&lt;/a&gt;, и на металинке много различных багов связанных с collect(например,&lt;small&gt; &quot;Bug 8912282: COLLECT+UNIQUE+ORDER DOES NOT REMOVE DUPLICATES&quot;, &quot;Bug 6145841: ORA-600[KOLOGSF2] ON CAST(COLLECT(..)) CALL&quot;,&quot;Bug 11802848: CAST/COLLECT DOES NOT WORK IN VERSION 11.2.0.2 WITH TYPE SYS.DBMS_DEBUG_VC2COLL&quot;, &quot;Bug 6996176: SELECT COLLECT DISTINCT GROUP BY STATEMENT RETURNS DUPLICATE VALUES&quot;&lt;/small&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Тестовая табличка&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;create table test_parallel parallel 8 as 
select mod(level,8) a, level b 
from dual 
connect by level&lt;=1000;
create index IX_TEST_PARALLEL on TEST_PARALLEL (A);
&lt;/pre&gt;
&lt;/div&gt;&lt;div class=&quot;spoiler&quot; title=&quot;Ошибки&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; select/*+ PARALLEL(2)*/ cast(collect(a) as number_table) from test_parallel ;
select/*+ PARALLEL(2)*/ cast(collect(a) as number_table) from test_parallel
*
ERROR at line 1:
ORA-12801: error signaled in parallel query server P000
ORA-21710: argument is expecting a valid memory address of an object

Elapsed: 00:00:00.12
DB11G/XTENDER&gt; select cast(collect(b) as number_table) from test_parallel group by a;
select cast(collect(b) as number_table) from test_parallel group by a
*
ERROR at line 1:
ORA-12805: parallel query server died unexpectedly

Elapsed: 00:00:17.57
&lt;/pre&gt;&lt;/div&gt;
А вот с медленным своим агрегатом таких ошибок нет. Стандартная дилемма: либо нестабильный, но быстрый collect, либо медленный свой агрегат...

&lt;div class=&quot;spoiler&quot; title=&quot;Пример агрегата&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;create or replace type ncollect_type as object
(
 
  data            sys.ku$_objnumset,
  
  static function ODCIAggregateInitialize
    ( sctx in out ncollect_type )
    return number ,

  member function ODCIAggregateIterate
    ( self  in out ncollect_type ,
      val   in     number
    ) return number ,
    
  member function ODCIAggregateDelete
    (  self in out  ncollect_type, 
       val  in      number
    ) return number ,
  member function ODCIAggregateTerminate
    ( self        in  ncollect_type,
      returnval   out sys.ku$_objnumset,
      flags in number
    ) return number ,
    
  member function ODCIAggregateMerge
    ( self in out ncollect_type,
      ctx2 in     ncollect_type
    ) return number
)
/
create or replace type body ncollect_type is

  static function ODCIAggregateInitialize
  ( sctx in out ncollect_type )
  return number
  is
  begin
    sctx := ncollect_type( sys.ku$_objnumset()) ;
    return ODCIConst.Success ;
  end;

  member function ODCIAggregateIterate
  ( self  in out ncollect_type ,
    val   in     number
  ) return number
  is
  begin
    self.data:=self.data multiset union sys.ku$_objnumset(val);
    return ODCIConst.Success;
  end;

  member function ODCIAggregateDelete
  (  self in out  ncollect_type, 
     val  in      number
  ) return number
  is
  begin
    self.data:=self.data multiset except sys.ku$_objnumset(val);
    return ODCIConst.Success;
  end;

  member function ODCIAggregateTerminate
  ( self        in  ncollect_type ,
    returnval   out sys.ku$_objnumset ,
    flags       in  number
  ) return number
  is
  begin
    returnval:=self.data;
    return ODCIConst.Success;
  end;
  
  member function ODCIAggregateMerge
  ( self in out ncollect_type ,
    ctx2 in     ncollect_type
  ) return number
  is
  begin
    self.data := self.data multiset union ctx2.data;
    return ODCIConst.Success;
  end;
end;
/
&lt;/pre&gt;&lt;/div&gt;И результаты:
&lt;table border=1&gt;&lt;tr&gt;&lt;th&gt;Вариант&lt;/th&gt;&lt;th&gt;Время(сек)&lt;/th&gt;&lt;/tr&gt;
&lt;tr style=&quot;background-color:#AAA&quot;&gt; &lt;td&gt;select/*+ NO_PARALLEL*/ cast(collect(b) as number_table) from test_parallel group by a;&lt;/td&gt; &lt;td&gt;0.03&lt;/td&gt; &lt;/tr&gt;
&lt;tr style=&quot;background-color:#AAA&quot;&gt; &lt;td&gt;select/*+ NO_PARALLEL*/ ncollect(b) from test_parallel group by a&lt;/td&gt; &lt;td&gt;0.08&lt;/td&gt; &lt;/tr&gt;
&lt;tr style=&quot;background-color:#AAA&quot;&gt; &lt;td&gt;select ncollect(b) from test_parallel group by a;&lt;/td&gt; &lt;td&gt;0.07&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;select/*+ NO_PARALLEL*/ collect(a) from test_parallel;&lt;/td&gt; &lt;td&gt;0.02&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;select/*+ NO_PARALLEL*/ ncollect(a) from test_parallel&lt;/td&gt; &lt;td&gt;0.18&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;select ncollect(a) from test_parallel;&lt;/td&gt; &lt;td&gt;0.19&lt;/td&gt; &lt;/tr&gt;
&lt;tr style=&quot;background-color:#AAA&quot;&gt; &lt;td&gt;select/*+ NO_PARALLEL*/ collect(b) from test_parallel;&lt;/td&gt; &lt;td&gt;0.02&lt;/td&gt; &lt;/tr&gt;
&lt;tr style=&quot;background-color:#AAA&quot;&gt; &lt;td&gt;select/*+ NO_PARALLEL*/ ncollect(b) from test_parallel&lt;/td&gt; &lt;td&gt;0.18&lt;/td&gt; &lt;/tr&gt;
&lt;tr style=&quot;background-color:#AAA&quot;&gt; &lt;td&gt;select ncollect(b) from test_parallel;&lt;/td&gt; &lt;td&gt;0.06&lt;/td&gt; &lt;/tr&gt;
&lt;/table&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/8838691070658492462/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/04/collect.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/8838691070658492462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/8838691070658492462'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/04/collect.html' title='Забавный факт о collect'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-8147890336846723911</id><published>2012-04-21T02:32:00.003+03:00</published><updated>2012-04-21T02:35:33.932+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="buffer sort"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle 11.2"/><category scheme="http://www.blogger.com/atom/ns#" term="select for update of"/><title type='text'>Появление buffer sort в oracle 11.2 в select for update</title><content type='html'>Начиная с 11.2.0.1 появилась новая строка &quot;buffer sort&quot; в планах с for update.&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; explain plan for
  2  select *
  3  from t_for_update
  4  where
  5    id=1
  6    and dt between date&#39;2012-01-01&#39;
  7               and date&#39;2012-01-02&#39;
  8  for update;

Explained.
DB11G/XTENDER&gt; select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
Plan hash value: 3273240857
--------------------------------------------------------------------------------------
| Id  | Operation          | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                 |     1 |    11 |     2   (0)| 00:00:01 |
|   1 |  FOR UPDATE        |                 |       |       |            |          |
|   2 |   BUFFER SORT      |                 |       |       |            |          |
|*  3 |    INDEX RANGE SCAN| IX_T_FOR_UPDATE |     1 |    11 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access(&quot;ID&quot;=1 AND &quot;DT&quot;&gt;=TO_DATE(&#39; 2012-01-01 00:00:00&#39;, &#39;syyyy-mm-dd
              hh24:mi:ss&#39;) AND &quot;DT&quot;&lt;=TO_DATE(&#39; 2012-01-02 00:00:00&#39;, &#39;syyyy-mm-dd
              hh24:mi:ss&#39;))
&lt;/pre&gt;
О причинах вкратце рассказывается &lt;a href=&quot;http://www.hellodba.com/reader.php?ID=177&amp;lang=en&quot;&gt;тут&lt;/a&gt;.
Цитата оттуда:
&lt;blockquote&gt;&quot;buffer sort&quot; is an operation to sort the data in private memory (sort area). However, there isn&#39;t any sort operation require in our query. We could understand that Oracle just adopt the mechanism to avoid read data from buffer cache when fetching data. Not only will it decrease the CR number, but also reduce latch requests.
&lt;/blockquote&gt;Правда тут кое-что неверно: Джонатан Льюис &lt;a href=&quot;http://jonathanlewis.wordpress.com/2006/12/17/buffer-sorts/&quot;&gt;поясняет&lt;/a&gt;, что операция buffer sort в таких случаях не включает сортировок. Вот вывод трассировки 10032 для for update с 32 записями:
&lt;pre&gt;---- Sort Statistics ------------------------------
Input records                             32
Output records                            32
Total number of comparisons performed     0
Total amount of memory used               2048
Uses version 1 sort
&lt;/pre&gt;В 10053 трассировке видно, что стоимостной оптимизатор не анализирует планы без buffer sort&#39;a, поэтому механизм прошит жестко и отключить его можно хинтом /*+ opt_param( &#39;optimizer_features_enable&#39; &#39;11.1.0.7&#39; ) */&lt;br /&gt;
или если так не работает, то optimizer_features_enable(&#39;11.1.0.7&#39;). Версию, естественно, ставить можно любую ниже 11.2.0.1</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/8147890336846723911/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/04/buffer-sort-oracle-112-select-for.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/8147890336846723911'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/8147890336846723911'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/04/buffer-sort-oracle-112-select-for.html' title='Появление buffer sort в oracle 11.2 в select for update'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-8630907902970988355</id><published>2012-04-21T00:32:00.000+03:00</published><updated>2012-11-24T10:49:29.362+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="index range scan"/><category scheme="http://www.blogger.com/atom/ns#" term="indexes"/><category scheme="http://www.blogger.com/atom/ns#" term="member of"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><title type='text'>Минусы использования &quot;member of&quot; с коллекциями и вложенными таблицами</title><content type='html'>&lt;script type=&quot;text/javascript&quot;&gt;
    jQuery(document).ready(function(){
        // Скрываем все спойлеры
        jQuery(&#39;.spoiler-body&#39;).hide()
        // по клику отключаем класс folded, включаем unfolded, затем для следующего
        // элемента после блока .spoiler-head (т.е. .spoiler-body) показываем текст спойлера
        jQuery(&#39;.spoiler-head&#39;).click(function(){
            jQuery(this).toggleClass(&quot;folded&quot;).toggleClass(&quot;unfolded&quot;).next().toggle()
        })
    })
&lt;/script&gt;&lt;br /&gt;
Давно хотел написать о минусах использования &lt;b&gt;&quot;a member of b&quot;&lt;/b&gt; перед обычными старыми вариантами вроде &lt;b&gt;a in (select column_value from table(b))&lt;/b&gt;.&lt;br /&gt;
Резюме: &lt;i&gt;&quot;member of&quot;&lt;/i&gt; в sql не умеет хорошо работать с индексами и использовать его желательно только в pl/sql - в этом случае по производительности практически одинаков с собственной функцией с циклом проверки(это покажу в самом конце).&lt;br /&gt;
&lt;br /&gt;
Рассмотрим два варианта использования member of:&lt;ol&gt;&lt;li&gt; запрос с условием, где поле таблицы должно входить в коллекцию&lt;/li&gt;
&lt;li&gt; запрос по таблице с вложенной таблицей и условием вхождения переменной во вложенную таблицу&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
И в первом и втором можно создать индексы, по которым отлично можно было бы искать необходимые поля с &lt;i&gt;index range/unique scan&lt;/i&gt;, но в случае с &lt;i&gt;member of&lt;/i&gt; ситуация гораздо хуже:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;В первом варианте можно добиться только &lt;i&gt;index fast full scan&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Во втором еще хуже: будет сначала фулл скан по родительской таблице, от нее index range scan по вложенной с access только по полю &lt;i&gt;nested_table_id &lt;/i&gt;- полю связи родительской с вложенной&lt;/li&gt;
&lt;/ul&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;div class=&quot;spoiler&quot; title=&quot;Подробнее...&quot;&gt;&lt;b&gt;&lt;center&gt;&lt;h2&gt;Вариант 1. Поиск записей по вхождению поля в заданную коллекцию&lt;/b&gt;&lt;/center&gt;&lt;/h2&gt;Рассмотрим сначала первый вариант - поиск где поле входит в коллекцию.&lt;br /&gt;
Текст примера:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;--drop table member_of_test1 purge;

create table member_of_test1(n primary key)
as
select level from dual connect by level&lt;1e5
/
begin
  dbms_stats.gather_table_stats(user,&#39;member_of_test1&#39;,cascade =&gt; true);
end;
/
explain plan for 
select * from member_of_test1 
where member_of_test1.n member of cast (:a as number_table)
/
select * from table(dbms_xplan.display)
/
explain plan for 
select * from member_of_test1 
where member_of_test1.n in (select column_value from table(cast (:a as number_table)))
/
select * from table(dbms_xplan.display)
/
&lt;/pre&gt;План с member of:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------

Plan hash value: 3157173230

-------------------------------------------------------------------------------------
| Id  | Operation         | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                 |  5000 | 25000 |    49   (7)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| MEMBER_OF_TEST1 |  5000 | 25000 |    49   (7)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(&quot;MEMBER_OF_TEST1&quot;.&quot;N&quot;MEMBER OFCAST(:A AS &quot;NUMBER_TABLE&quot;) )
&lt;/pre&gt;План с &quot;in (select * from table(:collection))&quot;:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------

Plan hash value: 3898737298

----------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |              |   255 |  1785 |    30   (4)| 00:00:01 |
|   1 |  NESTED LOOPS                       |              |   255 |  1785 |    30   (4)| 00:00:01 |
|   2 |   SORT UNIQUE                       |              |  8168 | 16336 |    29   (0)| 00:00:01 |
|   3 |    COLLECTION ITERATOR PICKLER FETCH|              |  8168 | 16336 |    29   (0)| 00:00:01 |
|*  4 |   INDEX UNIQUE SCAN                 | SYS_C0024557 |     1 |     5 |     0   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   4 - access(&quot;MEMBER_OF_TEST1&quot;.&quot;N&quot;=VALUE(KOKBF$))
&lt;/pre&gt;Разница очевидна: full table scan против index unique scan&#39;a! Кроме того, в варианте с &lt;i&gt;&quot;n in (select * from table(:collection))&quot;&lt;/i&gt; можно было бы еще и получить concatenation при использовании хинта &lt;i&gt;precompute_subquery&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;center&gt;&lt;h2&gt;Вариант 2. Поиск по вложенной таблице&lt;/b&gt;&lt;/center&gt;&lt;/h2&gt;&lt;br /&gt;
Cоздадим тестовую таблицу с nested table. sys.ku$_ObjNumSet - это table of number.&lt;br /&gt;
Кстати, с 11.2 в nested table уже автоматически создается индекс для &lt;i&gt;nested_table_id&lt;/i&gt;, поэтому следовать совету из &lt;a href=&quot;http://docs.oracle.com/cd/B28359_01/appdev.111/b28371/adobjdes.htm#sthref829&quot;&gt;11.1 &quot;Design Considerations for Nested Tables&quot;&lt;/a&gt;  уже &lt;a href=&quot;http://docs.oracle.com/cd/E16338_01/appdev.112/e11822/adobjdes.htm#sthref805&quot;&gt;не нужно&lt;/a&gt;, если цель только быстро доставать чайлдов из nested table от родителя.&lt;br /&gt;
Но т.к. мы хотим проверить поиск именно от nested table к родительской, то создадим свой&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;create table nt_test
(
  id integer
 ,nt sys.ku$_ObjNumSet
 ,primary key(id) using index( create unique index pk_nt_test on nt_test(id) )
)
nested table nt 
store as nt_table(
   (
    column_value not null
   ,constraint pk_nt_table primary key(nested_table_id,column_value)
   )
)
/
&lt;/pre&gt;На каждую запись из родительской вставим три во вложенной:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;insert into nt_test 
select level
      ,sys.ku$_ObjNumSet(level,level+1,level+2)
from dual
connect by level&lt;=1e4
/
&lt;/pre&gt;
еще создадим индекс, который по идее помог бы нам в поиске сначала по значениям в nested table:
&lt;pre class=&quot;brush: sql&quot;&gt;create index ix_nt_table_good on nt_table(column_value,nested_table_id);
&lt;/pre&gt;Т.к. мы знаем, что в родительской таблице автоматически создается индекс на поле связи с дочерней таблицей(nested_table_id), то попробуем его получить:
&lt;pre class=&quot;brush: sql&quot;&gt;col column_name format a30

select i.index_name,ic.TABLE_NAME ,ic.COLUMN_POSITION,ic.COLUMN_NAME 
from user_indexes i
    ,user_ind_columns ic
where 
    i.table_name=&#39;NT_TEST&#39;
and i.index_name=ic.INDEX_NAME;
&lt;/pre&gt;Вы увидите, что название этого столбца якобы соответствует названию nested table, которое было в ddl создания таблицы. Однако стоит только попытаться создать индекс с ним, и мы поймем что такого просто нет.
Зато можем его получить из &lt;i&gt;dba_cons_columns &lt;/i&gt;и сохранить, чтобы затем создать индекс с ним:
&lt;pre class=&quot;brush: sql&quot;&gt;column column_name new_val col_name;

select  c.constraint_name,c.constraint_type,c.table_name
       ,c.index_name
       ,cc.position
       ,cc.column_name
from user_constraints c
    ,user_cons_columns cc
where 
    c.owner=user
and c.table_name=&#39;NT_TEST&#39;
and c.constraint_type=&#39;U&#39;
and cc.owner=c.owner
and cc.constraint_name=c.constraint_name
;
-- создадим теперь полный индекс с этим полем связи:
create unique index ix_nt_test_parent on nt_test (&amp;col_name, id);
&lt;/pre&gt;Соберем статистику:
&lt;pre class=&quot;brush: sql&quot;&gt;begin
-- параметр cascade не включает сбор по вложенной таблице
  dbms_stats.gather_table_stats( user
                                ,&#39;NT_TEST&#39;
                                ,estimate_percent =&gt; 10
                                ,method_opt =&gt; &#39;FOR ALL COLUMNS SIZE 1&#39;
                                ,cascade =&gt; true
                                );
-- поэтому по ней тоже надо собирать:
  dbms_stats.gather_table_stats( user
                                ,&#39;NT_TABLE&#39;
                                ,estimate_percent =&gt; 10
                                ,method_opt =&gt; &#39;FOR ALL COLUMNS SIZE 1&#39;
                                ,cascade =&gt; true
                                );
end;
&lt;/pre&gt;Теперь наконец посмотрим какие планы получаются:
&lt;pre class=&quot;brush: sql&quot;&gt;-- План с member of:
explain plan for
select *
from nt_test t
where :n1 member of(nt);

select * from table(dbms_xplan.display);
----------------------------------
-- План с in (select * from table(...))
explain plan for
select *
from nt_test t
where :n1 in (select * from table(nt));

select * from table(dbms_xplan.display);
&lt;/pre&gt;&lt;b&gt;Member of&lt;/b&gt;:
&lt;pre class=&quot;brush: sql&quot;&gt;PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------

Plan hash value: 3175250264

----------------------------------------------------------------------------------
| Id  | Operation          | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |             |  9918 |   203K|    15   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN  | PK_NT_TABLE |     3 |    63 |     2   (0)| 00:00:01 |
|*  2 |  FILTER            |             |       |       |            |          |
|   3 |   TABLE ACCESS FULL| NT_TEST     |  9918 |   203K|    13   (0)| 00:00:01 |
|*  4 |   INDEX RANGE SCAN | PK_NT_TABLE |     3 |    63 |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access(&quot;NESTED_TABLE_ID&quot;=:B1)
   2 - filter(:N1MEMBER OF&quot;NT&quot;)
   4 - access(&quot;NESTED_TABLE_ID&quot;=:B1)
&lt;/pre&gt;&lt;b&gt;:value in (select * from table(nt))&lt;/b&gt;:
&lt;pre class=&quot;brush: sql&quot;&gt;PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------

Plan hash value: 3039725448

---------------------------------------------------------------------------------------
| Id  | Operation         | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                   |     3 |   126 |     5   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN | PK_NT_TABLE       |     3 |    63 |     2   (0)| 00:00:01 |
|   2 |  NESTED LOOPS     |                   |     3 |   126 |     5   (0)| 00:00:01 |
|*  3 |   INDEX RANGE SCAN| IX_NT_TABLE_GOOD  |     3 |    63 |     2   (0)| 00:00:01 |
|*  4 |   INDEX RANGE SCAN| IX_NT_TEST_PARENT |     1 |    21 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access(&quot;NESTED_TABLE_ID&quot;=:B1)
   3 - access(&quot;NT_TABLE&quot;.&quot;COLUMN_VALUE&quot;=TO_NUMBER(:N1))
   4 - access(&quot;NT_TABLE&quot;.&quot;NESTED_TABLE_ID&quot;=&quot;SYS_NC0000200003$&quot;)
&lt;/pre&gt;Как видно, в варианте &lt;i&gt;&quot;:value in (select * from table(nt))&quot;&lt;/i&gt; поиск происходит сразу по вложенной таблице с &lt;b&gt;Index range scan&lt;/b&gt; и &lt;i&gt;access &lt;/i&gt;по значению, в отличие от &lt;i&gt;&quot;member of&quot;&lt;/i&gt;, где сначала фулсканится родительская таблица и от нее уже по полю связи(NESTED_TABLE_ID) происходит lookup к вложенной таблице с фильтром по значению.

&lt;b&gt;&lt;center&gt;&lt;h2&gt;Вариант 3. &quot;Member of&quot; в PL/SQL&lt;/b&gt;&lt;/center&gt;&lt;/h2&gt;В PL/SQL особого смысла сравнивать, конечно, нет, но на всякий случай покажу, что использование member of вполне оправданно - по производительности лишь чуть-чуть проигрывает варианту с собственной функцией с компиляцией в native и plsql_optimize_level=3, зато универсальна и без лишних зависимостей.

Код примера:
&lt;pre class=&quot;brush: sql&quot;&gt;alter session set PLSQL_CODE_TYPE=NATIVE PLSQL_OPTIMIZE_LEVEL=3
/
create or replace function member_of2( p_element    integer
                                      ,p_collection sys.ku$_ObjNumSet
                                     ) 
                                     return boolean 
is
begin
  if p_element is null or p_collection is null then
    return null;
  else
    for i in p_collection.first..p_collection.last loop
      if p_element = p_collection(i) then
        return true;
      end if;
    end loop;
  end if;
exception when value_error then
  return false;
end;
/
declare
  a       sys.ku$_ObjNumSet:=sys.ku$_ObjNumSet();
  cnt     integer := 20000;
  b       integer := 0;
  l_timer integer := dbms_utility.get_time;
  procedure print(msg varchar2) is
  begin
    dbms_output.put_line(to_char((dbms_utility.get_time-l_timer)/100,&#39;9999.99&#39;)||&#39; &#39;||msg);
    l_timer:=dbms_utility.get_time;
  end;
  
begin
  a.extend(cnt);
  for i in 1..cnt loop
    a(i):=i;
  end loop;

  print(&#39;Start&#39;);

  b:=0;  
  for i in 1..cnt loop
    if i member of a then
      b:=b+1;
    end if;
  end loop;
  print(&#39;1 finished. b=&#39;||b);
  
  b:=0;
  for i in 1..cnt loop
    if member_of2(i,a) then
      b:=b+1;
    end if;
  end loop;
  print(&#39;2 finished. b=&#39;||b);
end;
/
&lt;/pre&gt;&lt;b&gt;Результат:&lt;ul&gt;&lt;li&gt;Member of - 8.75 сек.&lt;/li&gt;
&lt;li&gt;Собственная функция - 8.59.&lt;/li&gt;
&lt;/ul&gt;&lt;/b&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/8630907902970988355/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/04/member-of.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/8630907902970988355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/8630907902970988355'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/04/member-of.html' title='Минусы использования &quot;member of&quot; с коллекциями и вложенными таблицами'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-824337798889579452</id><published>2012-04-18T02:21:00.018+03:00</published><updated>2012-04-19T21:58:55.952+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="global temporary table"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="parallel"/><category scheme="http://www.blogger.com/atom/ns#" term="parallel_enable"/><title type='text'>Небольшой и опасный workaround для работы с gtt в pipelined функции с parallel_enable</title><content type='html'>&lt;script type=&quot;text/javascript&quot;&gt;
      $(function() {
         $(&#39;a#spoilerhead1&#39;).click(function() {
            $(&#39;div#example1&#39;).toggle();
            return false;
         });
         $(&#39;a#spoilerhead2&#39;).click(function() {
            $(&#39;div#example2&#39;).toggle();
            return false;
         });
      });   
&lt;/script&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.sql.ru/forum/actualthread.aspx?tid=934949&quot;&gt;Очередная задачка&lt;/a&gt; показалась мне интересной: Oracle очень плохо работает с временными таблицами(gtt - global temporary tables) в параллели.&lt;br /&gt;
&lt;p /&gt;Вообще у gtt в параллели в 11g куча ограничений, а до этого вообще запрещены:&lt;br /&gt;
10.2: &lt;a href=&quot;http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_7002.htm#sthref7490&quot;&gt;Restrictions on Temporary Tables&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;Parallel DML and parallel queries are not supported for temporary tables. Parallel hints are ignored. Specification of the parallel_clause returns an error.&lt;br /&gt;
&lt;/blockquote&gt;11.1: &lt;a href=&quot;http://docs.oracle.com/cd/B28359_01/server.111/b28313/usingpe.htm#CACEJACE&quot;&gt;Restrictions on Parallel DML&lt;/a&gt;&lt;br /&gt;
11.2: &lt;a href=&quot;http://docs.oracle.com/cd/E11882_01/server.112/e17118/statements_7002.htm#SQLRF54448&quot;&gt;Restrictions on Parallel DML&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;Parallel UPDATE, DELETE and MERGE are not supported for temporary tables.&lt;/blockquote&gt;&lt;br /&gt;
&lt;b&gt;Обновление:&lt;/b&gt;&lt;br /&gt;
Я был категорически не прав: в примере, который я привел ранее, данные gtt доступны только в одном слейве. Вообще доступность этих данных организуется каким-то хитрым способом, например, поглядите на данный пример:&lt;br /&gt;
&lt;a id=&quot;spoilerhead1&quot;&gt;«Показать код...»&lt;/a&gt;&lt;br /&gt;
&lt;div id=&quot;example1&quot; style=&quot;display: none;&quot;&gt;&lt;pre class=&quot;brush: sql&quot; &gt;drop table gtt_tab;
drop function test_parallel;

create global temporary table gtt_tab (i integer) on commit preserve rows parallel 8;
create or replace function test_parallel(p_cur sys_refcursor) return sys.ku$_objnumpairlist
    pipelined 
    parallel_enable (partition p_cur by any) 
    is
     l_row integer;
     l_cnt integer;
     l_sid integer;
    begin
      loop
        fetch p_cur into l_row;
        exit when p_cur%notfound;
        select count(*) into l_cnt from gtt_tab;
        l_sid := sys_context(&#39;USERENV&#39;,&#39;SID&#39;);
        pipe row (SYS.ku$_ObjNumPair(l_sid,l_cnt));
      end loop;  
    end;
/
insert into gtt_tab select level from dual connect by level&lt;=10000
/
select
  num1 sid,num2 cnt,count(*)
from
   table(
     test_parallel(cursor(select /*+ parallel(t,8) */ * from gtt_tab t))
   ) tt
group by num1,num2
/
&lt;/pre&gt;

Результат:
&lt;pre class=brush: sql&quot;&gt; &gt;&gt; select
  2    num1 sid,num2 cnt,count(*)
  3  from
  4     table(
  5       test_parallel(cursor(select /*+ parallel(t,8) */ * from gtt_tab t))
  6     ) tt
  7  group by num1,num2
  8  ;

       SID        CNT   COUNT(*)
---------- ---------- ----------
      4956          0       2080
      2981          0       2640
       336          0       2640
      1328          0       2640
&lt;/pre&gt;&lt;/div&gt;

&lt;a id=&quot;spoilerhead2&quot;&gt;«Ошибочный пример с видимостью только в одном слейве:»&lt;/a&gt;
&lt;div id=&quot;example2&quot; style=&quot;display: none;&quot;&gt;&lt;pre class=&quot;brush: sql&quot;&gt;truncate table gtt_tab;
drop function test_parallel_pipe;
drop table j_cur purge;
drop table gtt_tab purge;
drop type t_tab_row;
drop type t_row;

create or replace type t_row is object (
       i integer,
       n integer);
       
create or replace type t_tab_row is table of t_row;

create table j_cur parallel 8 as 
select level l from dual connect by level&lt;=10000;


create global temporary table gtt_tab (i integer) on commit preserve rows parallel 8;

create or replace function test_parallel_pipe(p_cur sys_refcursor) return t_tab_row 
    pipelined 
    parallel_enable (partition p_cur by any) 
    is
     v_row integer;
     v integer;
    begin
      loop
        fetch p_cur into v_row;
        exit when p_cur%notfound;
        for rec in (select count(*) v from gtt_tab) loop
           pipe row (t_row(v_row,rec.v));
        end loop;
      end loop;  
    end;
/
insert into gtt_tab values(1);
commit;
select 
   * 
from 
   table(
      test_parallel_pipe(
         cursor(
            select /*+ parallel(t,8) */ 
               t.l 
            from j_cur t
                ,(select 1 ignore from gtt_tab) t_ignore
         )
     )
   ) tt;
&lt;/pre&gt;
&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/824337798889579452/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/04/workaround-gtt-pipelined-parallelenable.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/824337798889579452'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/824337798889579452'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/04/workaround-gtt-pipelined-parallelenable.html' title='Небольшой и опасный workaround для работы с gtt в pipelined функции с parallel_enable'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-3452356652710216394</id><published>2012-04-08T19:31:00.000+03:00</published><updated>2012-04-08T19:31:10.663+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="PL/Scope"/><category scheme="http://www.blogger.com/atom/ns#" term="pl/sql"/><category scheme="http://www.blogger.com/atom/ns#" term="translation"/><category scheme="http://www.blogger.com/atom/ns#" term="перевод"/><title type='text'>Анализ PL/SQL кода в Oracle 11g (Перевод &quot;Zoom In on Your Code&quot; By Steven Feuerstein)</title><content type='html'>&lt;b&gt;Используйте PL/Scope для анализа вашего PL/SQL кода&lt;/b&gt;&lt;br /&gt;
&lt;p /&gt;С момента первого релиза PL/SQL, Oracle предоставляет набор представлений позволяющих разработчику получать информацию о PL/SQL объектах. Эти представления помогают нам понимать и анализировать наш код. Oracle Database 11g предоставляет еще более мощный аналитический инструмент - PL/Scope, собирающий информацию обо всех идентификаторах в вашем PL/SQL коде, которая затем доступна через представления словаря данных. Эти представления могут помочь отследить использование каждой переменной в определении, ссылках, вызовах, а также местоположение каждого вхождения переменной в исходном коде.&lt;br /&gt;
&lt;br /&gt;
Благодаря PL/Scope разработчики могут значительно лучше и легче выполнять анализ кода. Некоторые полезные приемы его использования и будут рассмотрены в данной статье.&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;h3&gt;&lt;b&gt;Включение PL/Scope&lt;/b&gt;&lt;/h3&gt;&lt;p /&gt;Чтобы использовать PL/Scope, необходимо сначала настроить компилятор на анализ идентификаторов во время компиляции. Вы можете сделать это, изменив значение параметра plscope_settings на уровне сеанса:&lt;br /&gt;
&lt;code&gt;ALTER SESSION SET plscope_settings=&#39;IDENTIFIERS:ALL&#39;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Существуют два возможных значения: IDENTIFIERS:ALL и IDENTIFIERS:NONE. По умолчанию - IDENTIFIERS:NONE. Вы можете увидеть значение  plscope_settings для каждой программной единицы с помощью запроса к [ALL/USER/DBA]_PLSQL_OBJECT_SETTINGS (прим переводчика: также как и другие полезные вещи, включая уровень pl/sql оптимизации и тд)&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;select name
      ,type
      ,plscope_settings
from USER_PLSQL_OBJECT_SETTINGS 
&lt;/pre&gt;&lt;i&gt;Описание USER_PLSQL_OBJECT_SETTINGS&lt;/i&gt;:&lt;br /&gt;
&lt;table border=&quot;1&quot;&gt;&lt;tr&gt;&lt;td&gt;&lt;br /&gt;
NAME                          &lt;/td&gt;&lt;td&gt;VARCHAR2(30)&lt;/td&gt;&lt;td&gt;Название объекта&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br /&gt;
TYPE                                   &lt;/td&gt;&lt;td&gt;VARCHAR2(12)&lt;/td&gt;&lt;td&gt;Тип объекта(Type,package,package body,procedure,function...)&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br /&gt;
PLSQL_OPTIMIZE_LEVEL                   &lt;/td&gt;&lt;td&gt;NUMBER&lt;/td&gt;&lt;td&gt;Уровень оптимизации(&lt;a href=&quot;http://docs.oracle.com/cd/B12037_01/server.101/b10755/initparams163.htm&quot;&gt;10g: 0-2&lt;/a&gt;, &lt;a href=&quot;http://docs.oracle.com/cd/E14072_01/server.112/e10820/initparams189.htm&quot;&gt;11g: 0-3&lt;/a&gt;)&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br /&gt;
PLSQL_CODE_TYPE                        &lt;/td&gt;&lt;td&gt;VARCHAR2(4000)&lt;/td&gt;&lt;td&gt;Тип компиляции: &lt;a href=&quot;http://dsvolk.blogspot.com/2010/08/plsql-native-compilation.html&quot;&gt;Interpreted/Native&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br /&gt;
PLSQL_DEBUG                            &lt;/td&gt;&lt;td&gt;VARCHAR2(4000)&lt;/td&gt;&lt;td&gt;Включен ли &lt;a href=&quot;http://docs.oracle.com/cd/E11882_01/server.112/e24448/initparams193.htm&quot;&gt;debug&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br /&gt;
PLSQL_WARNINGS                         &lt;/td&gt;&lt;td&gt;VARCHAR2(4000)&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;http://docs.oracle.com/cd/E14072_01/server.112/e10820/initparams191.htm&quot;&gt;Включен ли вывод предупреждений при компиляции&lt;/a&gt;.Кстати, &quot;любимый&quot; Кайтовский &quot;when others&quot; без raise обрел свое личное предупреждение-PLW-06009, а если установить параметр в &#39;ERRORS:ALL&#39;, то объект не будет скомпилирован пока не избавитесь от всех предупреждений&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br /&gt;
NLS_LENGTH_SEMANTICS                   &lt;/td&gt;&lt;td&gt;VARCHAR2(4000)&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;http://docs.oracle.com/cd/B19306_01/server.102/b14237/initparams127.htm&quot;&gt;Параметр сравнения длины строковых переменных: байты/символы&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br /&gt;
PLSQL_CCFLAGS                          &lt;/td&gt;&lt;td&gt;VARCHAR2(4000)&lt;/td&gt;&lt;td&gt;Переменные &lt;a href=&quot;http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/fundamentals.htm#BABIHIHF&quot;&gt;условной компиляции&lt;/a&gt;&lt;br /&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;br /&gt;
PLSCOPE_SETTINGS                       &lt;/td&gt;&lt;td&gt;VARCHAR2(4000)&lt;/td&gt;&lt;td&gt;IDENTIFIERS:ALL/ IDENTIFIERS:NONE&lt;br /&gt;
&lt;/table&gt;&lt;br /&gt;
У этого параметра есть два возможных значения: IDENTIFIERS:ALL и IDENTIFIERS:NONE. По умолчанию - IDENTIFIERS:NONE - сбор идентификаторов отключен.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;&lt;b&gt;Представление ALL_IDENTIFIERS&lt;/b&gt;&lt;/h3&gt;&lt;p /&gt;При компиляции объекта с включенным PL/Scope собирается информация обо всех идентификаторах используемых в объекте, которая доступна через представление ALL_IDENTIFIERS.&lt;br /&gt;
&lt;br /&gt;
Описание ALL_IDENTIFIERS:&lt;br /&gt;
&lt;table hspace=&quot;5&quot; width=&quot;100%&quot; vspace=&quot;5&quot; cellpadding=&quot;5&quot; border=&quot;1&quot; bgcolor=&quot;#dddddd&quot; align=&quot;center&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Столбец&lt;/strong&gt;&lt;/td&gt;     &lt;td&gt;&lt;strong&gt;Значение&lt;/strong&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OWNER&lt;/td&gt;     &lt;td&gt;Владелец объекта, содержащего идентификатор&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;NAME&lt;/td&gt;     &lt;td&gt;Имя идентификатора&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;TYPE&lt;/td&gt;     &lt;td&gt;Тип идентификатора, например: FORALL OUT (out аргумент), CONSTANT, PACKAGE,  or RECORD&lt;/td&gt;                      &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SIGNATURE&lt;/td&gt;     &lt;td&gt;Уникальная строка для каждого идентификатора сквозная для всех объектов, для однозначного определения из идентификаторов с одинаковыми именами(прим. переводчика: далее сигнатура)&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OBJECT_NAME&lt;/td&gt;     &lt;td&gt;Имя объекта&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OBJECT_TYPE&lt;/td&gt;     &lt;td&gt;Тип объекта, например: PACKAGE, TRIGGER, или PROCEDURE&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;USAGE&lt;/td&gt;     &lt;td&gt;Тип использования(объявление или присваивание)&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;USAGE_ID&lt;/td&gt;     &lt;td&gt;Порядковый номер вхождения идентификатора внутри объекта&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;USAGE_CONTEXT_ID&lt;/td&gt;     &lt;td&gt;Внешний ключ на родительский USAGE_ID; (например, контекст определения переменной - это имя подпрограммы, в которой эта переменная определена)&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LINE&lt;/td&gt;     &lt;td&gt;Порядковый номер строки вхождения переменной&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;COL&lt;/td&gt;     &lt;td&gt;Порядковый номер символа с начала строки места положения переменной&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt; &lt;/table&gt;Таблица 1: Описание ALL_IDENTIFIERS&lt;br /&gt;
&lt;br /&gt;
&lt;p/&gt;Вы можете получить информацию по определенному объекту следующим запросом:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT *
  FROM all_identifiers ai
 WHERE ai.owner = USER 
   AND ai.object_type = &#39;&amp;lt;program_type&amp;gt;&#39; 
   AND ai.object_name = &#39;&amp;lt;program_name&amp;gt;&#39;
ORDER BY line
&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;&lt;b&gt;Отслеживание использования переменной с помощью PL/Scope&lt;/b&gt;&lt;/h3&gt;&lt;p/&gt;PL/Scope сохраняет детальную информацию о каждом идентификаторе используемом  в вашем коде. Каждая строка в ALL_IDENTIFIERS относится к определенной строке определенного объекта. Тип использования указывается в столбце USAGES:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;ASSIGNMENT&lt;/b&gt; - присваивание - значение переменной в данном месте может измениться, то есть переменная находится либо в левой части оператора присваивания, либо находится в запросе в блоке INTO, либо передается OUT/IN OUT параметром.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CALL&lt;/b&gt; - вызов функции, процедуры или sql-запроса.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DECLARATION&lt;/b&gt; - объявление идентификатора.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;REFERENCE&lt;/b&gt; - обращение. Означает, что идентификатор используется без изменения значения, например: вызов исключения, передача идентификатора как IN или IN OUT параметр подпрограммы или списке USING блока EXECUTE IMMEDIATE, и использование идентификатора в определении %TYPE.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DEFINITION&lt;/b&gt; - определение: говорит компилятору как использовать или использовать объявленный ранее идентификатор. Следующие типы будут иметь строку с DEFINITION в ALL_IDENTIFIERS: FUNCTION, OBJECT, PACKAGE, PROCEDURE, TRIGGER, и EXCEPTION.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Если вы захотите увидеть все объявленные переменные в коде, вы можете выполнить следующий запрос:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT ai.object_name
     , ai.object_type
     , ai.name variable_name
     , ai.name context_name
  FROM all_identifiers ai
 WHERE ai.owner = USER AND 
       ai.TYPE = &#39;VARIABLE&#39; AND 
       ai.usage = &#39;DECLARATION&#39;
ORDER BY ai.object_name, 
ai.object_type, ai.usage_id
&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;&lt;b&gt;Использование usage_id для отображения иерархии идентификаторов&lt;/b&gt;&lt;/h3&gt;&lt;br /&gt;
Пакет может содержать несколько подпрограмм, которые также могут содержать один или несколько параметров. Вы можете использовать PL/Scope, чтобы показать эту иерархию. Покажем на примере пакета, представленного в Листинге 1.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Листинг 1:&lt;/b&gt; Код пакета plscope_demo&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;CREATE OR REPLACE PACKAGE plscope_demo
IS
   PROCEDURE my_procedure (param1_in IN INTEGER
                         , param2 IN employees.last_name%TYPE
                          );
END plscope_demo;
/
CREATE OR REPLACE PACKAGE BODY plscope_demo
IS
   PROCEDURE my_procedure (param1_in IN INTEGER
                         , param2 IN employees.last_name%TYPE
                          )
   IS
      c_no_such   CONSTANT NUMBER := 100;
      l_local_variable     NUMBER;
   BEGIN
      IF param1_in &gt; l_local_variable
      THEN
         DBMS_OUTPUT.put_line (param2);
      ELSE
         DBMS_OUTPUT.put_line (c_no_such);
      END IF;
   END my_procedure;
END plscope_demo;
/
&lt;/pre&gt;&lt;br /&gt;
Вы можете выполнить следующий иерархический запрос(Листинг 2), чтобы показать родителя строки в ALL_IDENTIFIERS в столбце usage_context_id.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Листинг 2:&lt;/b&gt; Запрос отображения иерархии идентификаторов&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;WITH plscope_hierarchy
        AS (SELECT line
                 , col
                 , name
                 , TYPE
                 , usage
                 , usage_id
                 , usage_context_id
              FROM all_identifiers
             WHERE     owner = USER
                   AND object_name = &#39;PLSCOPE_DEMO&#39;
                   AND object_type = &#39;PACKAGE BODY&#39;)
SELECT    LPAD (&#39; &#39;, 3 * (LEVEL - 1))
       || TYPE
       || &#39; &#39;
       || name
       || &#39; (&#39;
       || usage
       || &#39;)&#39;
          identifier_hierarchy
  FROM plscope_hierarchy
START WITH usage_context_id = 0
CONNECT BY PRIOR usage_id = usage_context_id
ORDER SIBLINGS BY line, col
/
&lt;/pre&gt;Результат запроса:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;PACKAGE PLSCOPE_DEMO (DEFINITION)
   PROCEDURE MY_PROCEDURE (DEFINITION)
      FORMAL IN PARAM1_IN (DECLARATION)
         SUBTYPE INTEGER (REFERENCE)
      FORMAL IN PARAM2 (DECLARATION)
      CONSTANT C_NO_SUCH (DECLARATION)
         CONSTANT C_NO_SUCH (ASSIGNMENT)
         NUMBER DATATYPE NUMBER (REFERENCE)
      VARIABLE L_LOCAL_VARIABLE (DECLARATION)
         NUMBER DATATYPE NUMBER (REFERENCE)
      FORMAL IN PARAM1_IN (REFERENCE)
      VARIABLE L_LOCAL_VARIABLE (REFERENCE)
&lt;/pre&gt;&lt;br /&gt;
&lt;h3&gt;&lt;b&gt;Использование Signature для отличия идентификаторов с одинаковыми именами&lt;/b&gt;&lt;/h3&gt;&lt;br /&gt;
Всегда можно найти вхождение строки в исходном коде поиском по представлению ALL_SOURCE. Также возможно использовать одно название переменной в нескольких различных элементах в вашем коде. К примеру, вы можете использовать в подпрограмме переменную с таким же названием:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;PROCEDURE plscope_demo_proc
IS
  plscope_demo_proc   NUMBER;
BEGIN
  DECLARE
    plscope_demo_proc   EXCEPTION;
  BEGIN
    RAISE plscope_demo_proc;
  END;

  plscope_demo_proc := 1;
END plscope_demo_proc;
&lt;/pre&gt;&lt;br /&gt;
Это очень запутанный, но это, безусловно, валидный код, и будет очень тяжело различить использование различных идентификаторов с этим имени в поиске по ALL_SOURCE.&lt;br /&gt;
&lt;br /&gt;
PL/Scope упрощает эту задачу, добавляя столбец SIGNATURE в представлении ALL_IDENTIFIERS. Каждый идентификатор имеет собственную сигнатуру - 32-байтную строку уникальную как внутри данной программной единицы (далее - юнит), так и вне ее (в отличие от USAGE_ID уникального только внутри своего юнита)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Листинг 3:&lt;/b&gt; Идентификаторы с одним именем&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT line
     , TYPE
     , usage
     , signature
  FROM all_identifiers
 WHERE     owner = USER
       AND object_name = &#39;PLSCOPE_DEMO_PROC&#39;
       AND name = &#39;PLSCOPE_DEMO_PROC&#39;
ORDER BY line

LINE  TYPE       USAGE        SIGNATURE                        
1     PROCEDURE  DEFINITION   51B3B5C5404AE8307DA49F42E0279915 
1     PROCEDURE  DECLARATION  51B3B5C5404AE8307DA49F42E0279915 
3     VARIABLE   DECLARATION  021B597943C0F31AD3938ACDAAF276F3 
6     EXCEPTION  DECLARATION  98E0183501FB350439CA44E3E511F60C 
8     EXCEPTION  REFERENCE    98E0183501FB350439CA44E3E511F60C 
11    VARIABLE   ASSIGNMENT   021B597943C0F31AD3938ACDAAF276F3
&lt;/pre&gt;&lt;br /&gt;
Заметьте, что каждая сигнатура появляется в выводе дважды. Для самой процедуры - DEFINITION и DECLARATION. Для переменных, констант, исключений и т.п. обязательно сначала будут строки с DECLARATION и лишь потом строки с такой же сигнатурой, показывающие строки кода в которых эти идентификаторы используются.&lt;br /&gt;
&lt;br /&gt;
С помощью сигнатур можно легко отфильтровать только те строки кода, в которых используется конкретный искомый идентификатор, несмотря на многочисленные идентификаторы с тем же именем. Например, в Листинге 4 запрашиваются все присваивания и обращения к переменной PLSCOPE_DEMO_PROC .&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Листинг 4:&lt;/b&gt; Запрос всех присваиваний и обращений к переменной PLSCOPE_DEMO_PROC&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT usg.line
     , usg.TYPE
     , usg.usage
  FROM all_identifiers dcl, 
      all_identifiers usg
 WHERE     
    dcl.owner = USER
 AND dcl.object_name = &#39;PLSCOPE_DEMO_PROC&#39;
 AND dcl.name = &#39;PLSCOPE_DEMO_PROC&#39;
 and dcl.usage = &#39;DECLARATION&#39;
 and dcl.type = &#39;VARIABLE&#39;
 and usg.signature = dcl.signature
 and usg.usage &lt;&gt; &#39;DECLARATION&#39;
ORDER BY line
&lt;/pre&gt;&lt;br /&gt;
Давайте теперь рассмотрим для чего еще можно использовать PL/Scope:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Проверка соглашений именования объектов и переменных&lt;/li&gt;
&lt;li&gt;Определение нарушений рекомендаций &quot;Best practices&quot;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;h3&gt;&lt;b&gt;Проверка соглашений именования объектов и переменных&lt;/b&gt;&lt;/h3&gt;&lt;br /&gt;
С помощью PL/Scope легко и просто различить типы идентификаторов (переменные, константы, параметры и т.д.), поэтому можно также проверять не нарушают ли они правила именования для своего типа.&lt;br /&gt;
&lt;p /&gt;К примеру, я следую следующим соглашениям при именовании параметров:&lt;br /&gt;
IN параметры заканчивается постфиксом &quot;_in&quot;&lt;br /&gt;
OUT параметры - _out&lt;br /&gt;
IN OUT параметры - _io&lt;br /&gt;
&lt;br /&gt;
&lt;p /&gt;Чтобы проверить следует ли юнит данным правилам, я посмотрю в строки с usage = declaration и типом FORMAL IN, FORMAL OUT или FORMAL IN OUT.&lt;br /&gt;
&lt;br /&gt;
&lt;p /&gt;Предположим, есть пакет с описанием, представленным в Листинге 5.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Листинг 5:&lt;/b&gt; Создание пакета plscope_demo&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;CREATE OR REPLACE PACKAGE plscope_demo
IS
   PROCEDURE my_procedure (param1_in IN INTEGER, param2 IN DATE);

   FUNCTION my_function (param1    IN INTEGER
                       , in_param2 IN DATE
                       , param3_in IN employees.last_name%TYPE
                        )
      RETURN VARCHAR2;
END plscope_demo;
&lt;/pre&gt;&lt;br /&gt;
Выполнив запрос из Листинга 6, мы можем найти нарушения правил именования параметров в данном пакете.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Листинг 6:&lt;/b&gt;Поиск нарушений правил именования&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT prog.name subprogram, parm.name parameter
  FROM all_identifiers parm, all_identifiers prog
 WHERE     parm.owner = USER
       AND parm.object_name = &#39;PLSCOPE_DEMO&#39;
       AND parm.object_type = &#39;PACKAGE&#39;
       AND prog.owner = parm.owner
       AND prog.object_name = parm.object_name
       AND prog.object_type = parm.object_type
       AND parm.usage_context_id = prog.usage_id
       AND parm.TYPE IN (&#39;FORMAL IN&#39;, &#39;FORMAL IN OUT&#39;, &#39;FORMAL OUT&#39;)
       AND parm.usage = &#39;DECLARATION&#39;
       AND ( (parm.TYPE = &#39;FORMAL IN&#39;
              AND LOWER (parm.name) NOT LIKE &#39;%\_in&#39; ESCAPE &#39;\&#39;)
            OR (parm.TYPE = &#39;FORMAL OUT&#39;
                AND LOWER (parm.name) NOT LIKE &#39;%\_out&#39; ESCAPE &#39;\&#39;)
            OR (parm.TYPE = &#39;FORMAL IN OUT&#39;
                AND LOWER (parm.name) NOT LIKE &#39;%\_io&#39; ESCAPE &#39;\&#39;))
ORDER BY prog.name, parm.name
&lt;/pre&gt;&lt;br /&gt;
Обратите внимание на использование usage_context_id для поиска подпрограммы-&quot;владельца&quot; параметра.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;&lt;b&gt;Определение нарушений рекомендаций &quot;Best practices&quot;&lt;/b&gt;&lt;/h3&gt;&lt;br /&gt;
В дополнение к предупреждениям при компиляции PL/Scope предлагает отличный способ реализации собственных проверок на нарушения рекомендаций. Ниже два сценария проверки, которые было бы тяжело реализовать простым сканированием исходного кода:&lt;br /&gt;
&lt;br /&gt;
&lt;p /&gt;&lt;b&gt;Переменные декларированные в спецификации пакета.&lt;/b&gt; Это опасно тем, что любой пользователь с правом execute на пакет может читать и менять содержимое этих переменных напрямую.&lt;br /&gt;
&lt;br /&gt;
&lt;p /&gt;&lt;b&gt;Объявленные, но не используемые в коде исключения.&lt;/b&gt; Разработчики могут объявить собственные исключения в блоке и, если они не используются, то от них желательно избавиться.(Это же, кстати, относится и к неиспользуемым переменным)&lt;br /&gt;
&lt;br /&gt;
Чтобы проверить объявленные переменные в спецификации пакета, мы должны их сначала найти. Это довольно просто:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT object_name, name, line
  FROM all_identifiers ai
 WHERE ai.owner = USER
     AND ai.TYPE = &#39;VARIABLE&#39;
     AND ai.usage = &#39;DECLARATION&#39;
     AND ai.object_type = &#39;PACKAGE&#39;
&lt;/pre&gt;&lt;br /&gt;
Чтобы проверить объявленные, но не вызываемые исключения, нужно сначала понять какие значения USAGE возможны для исключений. Рассмотрим следующую процедуру:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;PROCEDURE plscope_demo_proc
IS
   e_bad_data   EXCEPTION;
   PRAGMA EXCEPTION_INIT (
                e_bad_data, -20900);
BEGIN
   RAISE e_bad_data;
EXCEPTION
   WHEN e_bad_data
   THEN
      log_error ();
END plscope_demo_proc;
&lt;/pre&gt;Посмотрим, что покажет PL/Scope об идентификаторе &quot;e_bad_data&quot;:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;SELECT line
     , TYPE
     , usage
  FROM all_identifiers
 WHERE owner = USER
   AND object_name = 
              &#39;PLSCOPE_DEMO_PROC&#39;
   AND name = &#39;E_BAD_DATA&#39;
ORDER BY line
/

LINE  TYPE       USAGE
-----  ------------  ---------------
3     EXCEPTION  DECLARATION 
4     EXCEPTION  ASSIGNMENT  
6     EXCEPTION  REFERENCE   
8     EXCEPTION  REFERENCE  
&lt;/pre&gt;Из этого можно сделать вывод, что EXCEPTION_INIT отображается как &lt;i&gt;assignment&lt;/i&gt; - присваивание именованному исключению кода ошибки, а RAISE и WHEN - как &lt;i&gt;references&lt;/i&gt; - использование. &lt;br /&gt;
Исходя из этого, мы можем найти все исключения, которые объявлены, но используются в коде:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Листинг 7:&lt;/b&gt;Запрос всех объявленных, но неиспользуемых исключений&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;WITH subprograms_with_exception
        AS (SELECT DISTINCT owner
                          , object_name
                          , object_type
                          , name
              FROM all_identifiers has_exc
             WHERE     has_exc.owner = USER
                   AND has_exc.usage = &#39;DECLARATION&#39;
                   AND has_exc.TYPE = &#39;EXCEPTION&#39;),
     subprograms_with_raise_handle
        AS (SELECT DISTINCT owner
                          , object_name
                          , object_type
                          , name
              FROM all_identifiers with_rh
             WHERE     with_rh.owner = USER
                   AND with_rh.usage = &#39;REFERENCE&#39;
                   AND with_rh.TYPE = &#39;EXCEPTION&#39;)
SELECT *
  FROM subprograms_with_exception
MINUS
SELECT *
  FROM subprograms_with_raise_handle
&lt;/pre&gt;&lt;br /&gt;
Я реализовал многие из показанных в статье запросов в одном пакете доступном на &lt;a href=&quot;http://www.oracle.com/technetwork/issue-archive/2010/10-sep/o50plsql-165565.zip&quot;&gt;http://www.oracle.com/technetwork/issue-archive/2010/10-sep/o50plsql-165565.zip&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;hr&gt;&lt;b&gt;Стивен Фейерштейн&lt;/b&gt; (steven.feuerstein@quest.com)&lt;br /&gt;
&lt;br /&gt;
Оригинал статьи:&lt;a href=&quot;http://www.oracle.com/technetwork/issue-archive/2010/10-sep/o50plsql-165471.html&quot;&gt;http://www.oracle.com/technetwork/issue-archive/2010/10-sep/o50plsql-165471.html&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/3452356652710216394/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/04/plsql-oracle-11g-zoom-in-on-your-code.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/3452356652710216394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/3452356652710216394'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/04/plsql-oracle-11g-zoom-in-on-your-code.html' title='Анализ PL/SQL кода в Oracle 11g (Перевод &quot;Zoom In on Your Code&quot; By Steven Feuerstein)'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4791872513565348125.post-5882292995647796974</id><published>2012-03-22T22:53:00.006+03:00</published><updated>2012-04-27T19:41:26.403+03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="compare"/><category scheme="http://www.blogger.com/atom/ns#" term="oracle"/><category scheme="http://www.blogger.com/atom/ns#" term="session_user"/><category scheme="http://www.blogger.com/atom/ns#" term="sys_context"/><category scheme="http://www.blogger.com/atom/ns#" term="user"/><title type='text'>Сравнение скорости функций user vs sys_context(&#39;USERENV&#39;,&#39;SESSION_USER&#39;)</title><content type='html'>Сегодня очень удивился заметив, что вызов &lt;i&gt;&lt;b&gt;&quot;username:=user;&quot;&lt;/b&gt;&lt;/i&gt; и &lt;i&gt;&lt;b&gt;&quot;select user into username from dual;&quot;&lt;/b&gt;&lt;/i&gt; одинаковы по времени выполнения, в отличие от десятикратной разницы &lt;i&gt;&lt;b&gt;dt:=sysdate&lt;/b&gt;&lt;/i&gt; и &lt;i&gt;&lt;b&gt;select sysdate into dt from dual;&lt;/b&gt;&lt;/i&gt;. Оказалось все просто, стоило лишь поглядеть трассировку или поглядеть код пакета sys.standard: PL/SQL-ный &lt;i&gt;USER&lt;/i&gt; содержит внутри рекурсивный запрос c вызовом sql-ного user: &lt;b&gt;&lt;i&gt;&quot;select user from sys.dual&quot;&lt;/i&gt;&lt;/b&gt;.&lt;br /&gt;
Из кода &lt;b&gt;standard&lt;/b&gt;:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;function USER return varchar2 is
  c varchar2(255);
  begin
        select user into c from sys.dual;
        return c;
  end;

  -- Bug 1287775: back to calling ICD.
  -- Special: if the ICD raises ICD_UNABLE_TO_COMPUTE, that means we should do
  -- the old &#39;SELECT SYSDATE FROM DUAL;&#39; thing.  This allows us to do the
  -- SELECT from PL/SQL rather than having to do it from C (within the ICD.)
  function sysdate return date is
    d date;
  begin
    d := pessdt;
    return d;
  exception
    when ICD_UNABLE_TO_COMPUTE then
      select sysdate into d from sys.dual;
      return d;
  end;

  -- Special: if the ICD raises ICD_UNABLE_TO_COMPUTE, that means we should do
  -- the old &#39;select sys_context(...) from dual;&#39; thing.  This allows us to do
  -- the select from PL/SQL rather than having to do it from C (within the ICD.)
  function SYS_CONTEXT(namespace varchar2, attribute varchar2)
    return varchar2 is
  c varchar2(4000);
  BEGIN
    c := pessysctx2(namespace, attribute);
    return c;
  exception
    when ICD_UNABLE_TO_COMPUTE then
      select sys_context(namespace,attribute) into c from sys.dual;
      return c;
  end;
&lt;/pre&gt;&lt;br /&gt;
И самое главное: user в 10 раз с лишним медленнее, чем sys_context(&#39;USERENV&#39;,&#39;SESSION_USER&#39;)!&lt;br /&gt;
У user, видимо, все это время съедает переключение контекста, а исключение ICD_UNABLE_TO_COMPUTE  в sys_context непроисходит(как и в случае с sysdate).&lt;br /&gt;
&lt;p&gt;Я проверял на 10.2.0.4, 10.2.0.5, 11.2.0.1, 11.2.0.3 с plsql_optimization_level=2  результаты практически одинаковы, поэтому показываю только один:&lt;br /&gt;
&lt;pre class=&quot;brush: sql&quot;&gt;DB11G/XTENDER&gt; declare
  2    username varchar2(30);
  3  begin
  4    for i in 1..5e5 loop
  5      username:=user;
  6    end loop;
  7  end;
  8  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:10.86
DB11G/XTENDER&gt; declare
  2    username varchar2(30);
  3  begin
  4    for i in 1..5e5 loop
  5      username:=sys_context(&#39;USERENV&#39;,&#39;SESSION_USER&#39;);
  6    end loop;
  7  end;
  8  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.02
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.xt-r.com/feeds/5882292995647796974/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.xt-r.com/2012/03/user-vs-syscontextuserenvsessionuser.html#comment-form' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/5882292995647796974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4791872513565348125/posts/default/5882292995647796974'/><link rel='alternate' type='text/html' href='http://www.xt-r.com/2012/03/user-vs-syscontextuserenvsessionuser.html' title='Сравнение скорости функций user vs sys_context(&#39;USERENV&#39;,&#39;SESSION_USER&#39;)'/><author><name>Sayan Malakshinov</name><uri>http://www.blogger.com/profile/11087163803358489777</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>