(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Проталкивание условия в представлениях, содержащих аналитические функции

У меня в базе данных есть представление, содержащее аналитическую функцию. Аналитическая функция проходит окном по набору строк таблицы и возвращает их подмножество. Начальное тестирование использования этого представления дало весьма многообещающие результаты, поскольку при использовании аналитической функции серверу для получения ответа потребовалось выполнить НАМНОГО меньше действий, чем при соединении таблицы с самой собой (ранее использовался такой подход). При этом использовались запросы к представлению, отбирающие данные по тому же столбцу, по которому выполнялось секционирование таблицы в аналитической функции. Однако, когда в запросе к представлению я задал условие по другому столбцу в конструкции WHERE, производительность существенно снизилась. Мое исследование показало, что условие не было протолкнуто в представление, и в результате пришлось читать всю таблицу, разбивать на секции и запоминать, прежде чем было применено условие.

Нет ли способа принудительно протолкнуть условие в представление? Я пытался использовать подсказки вроде PUSH_PRED, но так и не смог ничего добиться. Нет ли другого способа построить представление для получения необходимых мне данных?

Ниже представлен длинный фрагмент сеанса SQL*Plus, в котором описаны подробности проведенного исследования.

SQL>drop table t;

Table dropped.

Elapsed: 00:00:00.41
SQL>create table t( Group_id    VARCHAR2(32),
  2                  Group_Key   NUMBER,
  3                  col2        NUMBER );

Table created.

Elapsed: 00:00:00.40
SQL>insert into t
  2      select object_name,
  3             ROW_NUMBER() OVER( partition by object_name
  4                                order by object_id ),
  5             object_id
  6      from all_objects
  7      where rownum<=25000
  8  /

24862 rows created.

Elapsed: 00:00:10.05
SQL>insert into t
  2      select Group_id // '1',
  3             Group_Key,
  4             col2 * -1
  5      from t
  6  /

24862 rows created.

Elapsed: 00:00:02.03
SQL>commit;

Commit complete.

Elapsed: 00:00:00.90
SQL>-- Создаем индексы по 2 столбцам.
SQL>-- Один - по столбцу, используемому для секционирования в аналитической функции
SQL>-- Другой - по еще одному столбцу таблицы
SQL>create index IDX_T_GRPID on T(GROUP_ID);

Index created.

Elapsed: 00:00:08.63
SQL>create index IDX_T_COL2 on T(COL2);

Index created.

Elapsed: 00:00:09.05
SQL>-- Вычисляем статистическую информацию для CBO
SQL>analyze table t compute statistics;

Table analyzed.

Elapsed: 00:00:14.51
SQL>-- Создаем пакет, который будет использоваться для отслеживания
SQL>--   количества строк, обработанных аналитической функцией.
SQL>-- Он также будет использоваться, чтобы отбросить некоторые строки,
SQL>--   обработанные аналитической функцией.
SQL>create or replace package test_anafunc is
  2      function test_func( x NUMBER ) return number;
  3  
  4      function get_Count return number;
  5      procedure reset_count;
  6  end;
  7  /

Package created.

Elapsed: 00:00:00.70
SQL>create or replace package body test_anafunc is
  2  
  3      p_Count     NUMBER(38);
  4  
  5      function test_func( x NUMBER ) return number is
  6      begin
  7          p_Count := p_Count + 1;
  8  
  9          if( x > 1 ) then
 10              return 1;
 11          end if;
 12  
 13          return 0;
 14      end test_func;
 15  
 16      function get_Count return number is
 17      begin
 18          return p_Count;
 19      end get_Count;
 20  
 21      procedure reset_count is
 22      begin
 23          p_Count := 0;
 24      end reset_Count;
 25  
 26  begin
 27      p_Count := 0;
 28  end;
 29  /

Package body created.

Elapsed: 00:00:00.70
SQL>-- Создаем представление, содержащее аналитическую функцию.
SQL>-- Оно имитирует представление, которое будет открыто приложением
SQL>--   конченым пользователям.
SQL>create or replace view test_view as
  2  select a.group_id, a.group_key, a.col2
  3  from (select t.group_id, t.group_key, t.col2,
  4               ROW_NUMBER() OVER( PARTITION BY GROUP_ID
  5                                  ORDER BY GROUP_KEY ASC NULLS LAST ) RNUM
  6        from t
  7        where test_anafunc.test_func(GROUP_KEY) = 1 ) a
  8  where a.RNUM = 1
  9  /

View created.

Elapsed: 00:00:00.90
SQL>-- Давайте посмотрим, как выполняются запросы к этому представлению.
SQL>
SQL>-- Запрашиваем представление по group_id.
SQL>--   Выбираем такое значение из таблицы t, для которого есть более одной строки.
SQL>-- Мы должны увидеть вторую строку группы (Group_key=2).
SQL>-- План выполнения должен показывать использование индекса.
SQL>-- Вызов test_anafunc.get_Count должен вернуть количество строк для
SQL>--   соответствующего значения group_id.
SQL>-- Это показывает, что условие протолкнуто во вложенное представление.
SQL>execute test_anafunc.reset_Count

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.10
SQL>set autotrace on explain statistics
SQL>select * from test_View where group_id = 'TRACE';

GROUP_ID                          GROUP_KEY       COL2
-------------------------------- ---------- ----------
TRACE                                     2       7942

Elapsed: 00:00:00.21

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=5 Card=1 Bytes=57)
   1    0   VIEW (Cost=5 Card=1 Bytes=57)
   2    1     WINDOW (SORT)
   3    2       TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=3 Card=1 Bytes=27)
   4    3         INDEX (RANGE SCAN) OF 'IDX_T_GRPID' (NON-UNIQUE) (Cost=1 Card=1)

Statistics
----------------------------------------------------------
         42  recursive calls
          0  db block gets
          9  consistent gets
          0  physical reads
          0  redo size
        486  bytes sent via SQL*Net to client
        425  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          3  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL>set autotrace off
SQL>select test_anafunc.get_Count from sys.dual;

 GET_COUNT
----------
         7

Elapsed: 00:00:00.20
SQL>-- Запрос по столбцу, не использованному для секционирования.
SQL>--   Выбираем object_id, существующий в таблице t в столбце col2.
SQL>-- Должны получить одну строку.
SQL>-- Однако, план выполнения не покажет использования индекса. Вместо
SQL>--   этого вы увидите полный просмотр таблицы.
SQL>-- Вызов test_anafunc.get_Count вернет значение, равное общему
SQL>--    количеству строк.
SQL>-- Это показывает, что условие НЕ протолкнуто во вложенное представление
SQL>--   и что мы обрабатываем всю таблицу, а не только те строки,
SQL>--   которые удовлетворяют условиям конструкции where.
SQL>execute test_anafunc.reset_Count

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.10
SQL>/

 GET_COUNT
----------
         0

Elapsed: 00:00:00.10
SQL>set autotrace on explain statistics
SQL>select * from test_view where col2 = 10816;

GROUP_ID                          GROUP_KEY       COL2
-------------------------------- ---------- ----------
ADDRESSLOCATION_SDOGEOM                   2      10816

Elapsed: 00:00:05.58

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=40 Card=498 Bytes=28386)
   1    0   VIEW (Cost=40 Card=498 Bytes=28386)
   2    1     WINDOW (SORT)
   3    2       TABLE ACCESS (FULL) OF 'T' (Cost=36 Card=498 Bytes=13446)

Statistics
----------------------------------------------------------
         50  recursive calls
         11  db block gets
        242  consistent gets
        251  physical reads
          0  redo size
        505  bytes sent via SQL*Net to client
        425  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          2  sorts (memory)
          1  sorts (disk)
          1  rows processed

SQL>set autotrace off
SQL>select test_anafunc.get_Count from sys.dual;

 GET_COUNT
----------
     49724

Elapsed: 00:00:00.10
SQL>-- Сравните это с тем, что я хотел бы получить для запроса по col2.
SQL>execute test_anafunc.reset_Count

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.10
SQL>/

 GET_COUNT
----------
         0

Elapsed: 00:00:00.10
SQL>set autotrace on explain statistics
SQL>select a.group_id, a.group_key, a.col2
  2  from (select t.group_id, t.group_key, t.col2,
  3               ROW_NUMBER() OVER( PARTITION BY GROUP_ID
  4                                  ORDER BY GROUP_KEY ASC NULLS LAST ) RNUM
  5        from t
  6        where test_anafunc.test_func(GROUP_KEY) = 1
  7            and col2 = 10816 ) a
  8  where a.RNUM = 1
  9  /

GROUP_ID                          GROUP_KEY       COL2
-------------------------------- ---------- ----------
ADDRESSLOCATION_SDOGEOM                   2      10816

Elapsed: 00:00:00.11

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=57)
   1    0   VIEW (Cost=4 Card=1 Bytes=57)
   2    1     WINDOW (SORT)
   3    2       TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=1 Bytes=27)
   4    3         INDEX (RANGE SCAN) OF 'IDX_T_COL2' (NON-UNIQUE) (Cost=1 Card=1)

Statistics
----------------------------------------------------------
         35  recursive calls
          0  db block gets
          7  consistent gets
          0  physical reads
          0  redo size
        505  bytes sent via SQL*Net to client
        425  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          3  sorts (memory)
          0  sorts (disk)
          1  rows processed

SQL>set autotrace off
SQL>select test_anafunc.get_Count from sys.dual
  2  /

 GET_COUNT
----------
         1

Elapsed: 00:00:00.10

Ответ Тома Кайта

Этого нельзя сделать - при этом ИЗМЕНИТСЯ ответ. Вы думаете, что ваши два запроса эквивалентны, но это НЕ ТАК.

Есть ОГРОМНАЯ разница между

select analytic function
  from t
 where <условие>

и

select * 
  from ( select analytic function
           from t )
 where <условие>

Они даже и близко НЕ СРАВНИМЫ. Вообще.

Этот запрос говорит:

SQL>select a.group_id, a.group_key, a.col2
  2  from (select t.group_id, t.group_key, t.col2,
  3               ROW_NUMBER() OVER( PARTITION BY GROUP_ID
  4                                  ORDER BY GROUP_KEY ASC NULLS LAST ) RNUM
  5        from t
  6        where test_anafunc.test_func(GROUP_KEY) = 1
  7            and col2 = 10816 ) a
  8  where a.RNUM = 1
  9  /

Выбери строки из T, пропуская строки с group_key 1 (это делает test_func), и выбирая те, в которых col2 = 10816.

Затем, для всех таких строк - секционируй по group_id и отсортируй по group_key, присваивая row_number.

Затем, оставь только первую строку.

А этот запрос:

select * 
 from (select a.group_id, a.group_key, a.col2
    from (select t.group_id, t.group_key, t.col2,
                 ROW_NUMBER() OVER( PARTITION BY GROUP_ID
                                    ORDER BY GROUP_KEY ASC NULLS LAST ) RNUM
          from t
          where test_anafunc.test_func(GROUP_KEY) = 1 ) a
 where col2 = 10816 
   and a.RNUM = 1
/

говорит:

Найди все строки, в которых group_key не равен 1. Секционируй их по group_id. Отсортируй по group_key и присвой row_number.

Теперь, когда это сделано, оставь только первую строку ПРИ УСЛОВИИ, что в ней col2 = 10816.

Вот доказательство того, что эти запросы отличаются - они ВЕСЬМА, ВООБЩЕ и полностью отличаются:

ops$tkyte@ORA817DEV.US.ORACLE.COM> drop table t
  2  /

Table dropped.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table t( Group_id    VARCHAR2(32),
  2                   Group_Key   NUMBER,
  3                   col2        NUMBER )
  4  /

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'x', 2, 10815 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into t values ( 'x', 3, 10816 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace view test_view as
  2   select a.group_id, a.group_key, a.col2
  3   from (select t.group_id, t.group_key, t.col2,
  4                ROW_NUMBER() OVER( PARTITION BY GROUP_ID
  5                                   ORDER BY GROUP_KEY ASC NULLS LAST ) RNUM
  6         from t
  7         where test_anafunc.test_func(GROUP_KEY) = 1 ) a
  8   where a.RNUM = 1
  9  /

View created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> select * from test_view where col2 = 10816;

no rows selected

ops$tkyte@ORA817DEV.US.ORACLE.COM> select *
  2    from (
  3   select a.group_id, a.group_key, a.col2
  4   from (select t.group_id, t.group_key, t.col2,
  5                ROW_NUMBER() OVER( PARTITION BY GROUP_ID
  6                                   ORDER BY GROUP_KEY ASC NULLS LAST ) RNUM
  7         from t
  8         where test_anafunc.test_func(GROUP_KEY) = 1 ) a
  9   where a.RNUM = 1
 10   )
 11   where col2 = 10816
 12  /

no rows selected

ops$tkyte@ORA817DEV.US.ORACLE.COM> select a.group_id, a.group_key, a.col2
  2   from (select t.group_id, t.group_key, t.col2,
  3                ROW_NUMBER() OVER( PARTITION BY GROUP_ID
  4                                   ORDER BY GROUP_KEY ASC NULLS LAST ) RNUM
  5         from t
  6         where test_anafunc.test_func(GROUP_KEY) = 1
  7             and col2 = 10816 ) a
  8   where a.RNUM = 1
  9  /

GROUP_ID                          GROUP_KEY       COL2
-------------------------------- ---------- ----------
x                                         3      10816

Делаю ли я запрос к представлению или запрос с вложенным представлением - данных нет (по определению - такой запрос не должен возвращать данных).

Делаем так, как вы хотите - и получаем строку. Но это потому, что задавался абсолютно другой вопрос!

Достаточно ясно :)

Я подозревал, что причина такого поведения - изменение ответа. Спасибо за хороший пример, который это доказал.

Не могли бы вы предложить другой подход для получения того, что мне нужно? Важно, чтобы результаты каждого запроса к таблице обрабатывались аналитической функцией. Т.е. какие бы условия пользователь/приложение не задавали бы для поиска подмножества строк, надо прогнать их через функцию test_func для сокращения количества, а затем, для оставшегося набора строк, надо применить аналитическую функцию с окном, для выбора одной из них (RNUM=1).

Моя проблема лишь в том, что я не могу сформулировать корректный SQL-оператор для такого требования? Или этого просто нельзя сделать, используя представления с аналитическими функциями?

Я вынужден использовать представление, потому что аналитические функции нельзя использовать в конструкции WHERE. Но если бы и не это, я хотел бы, чтобы из приложения запрос шел к представлению, чтобы оно "видело" только часть столбцов таблицы.

Я знаю другие способы решения проблемы, но они не настолько просты, как использование аналитических функций (если только мне удастся их применить). :)

Ответ Тома Кайта

В таком случае, ваши требования нельзя удовлетворить с помощью представления.

Условия всегда будут применяться ПОСЛЕ вычисления аналитических функций в представлении, они должны проверяться именно так. Потому, что:

select analytic
 from t
 where  условие 

СИЛЬНО и ВСЕГДА отличается от

select * 
from ( select analytic
         from t )
 where  условие 

Проблема, по сути, в том, что из одного нельзя получить другое.

Высказанная вами причина использования представления не связана с требованиями. МОЖНО использовать результат аналитической функции в условии (вы ИСПОЛЬЗУЕТЕ - rnum = 1)!!! Это просто надо делать ПОСЛЕ, а не ПО ХОДУ.

Это аналогично функциям агрегирования. Нельзя сказать: where count(*) = 1, надо говорить HAVING count(*) = 1. Условие проверяется ПОСЛЕ построения результирующего множества. С аналитическими функциями - то же самое.

Я уверен, что вы можете использовать аналитические функции (я знаю это).

Я также знаю, что вам не удастся использовать представление при указанном списке "обязательных требований".

Как заставить работать no_push_pred?

У меня есть запрос:

select ename, dname
from (select * from emp where deptno = 10) a,
     (select * from dept where deptno = 10) b
where a.empno = 7934;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=21)
   1    0   NESTED LOOPS (Cost=3 Card=1 Bytes=21)
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'EMP' (Cost=1 Card=1 Bytes=10)
   3    2       INDEX (UNIQUE SCAN) OF 'EMP_PK' (UNIQUE)
   4    1     TABLE ACCESS (FULL) OF 'DEPT' (Cost=2 Card=1 Bytes=11)

Я думаю, что происходит проталкивание условия (where empno... ) в представление, поэтому я изменил запрос следующим образом:

select /*+ NO_PUSH_PRED(a) */ ename, dname
from (select * from emp where deptno = 10) a,
     (select * from dept where deptno = 10) b
where a.empno = 7934;

но получил тот же план выполнения, тогда как ожидал два полных просмотра таблиц emp и dept...

Как работает эта подсказка?

Ответ Тома Кайта

Она работает в случае соединения. А это не соединение. Вы можете использовать no_merge для получения альтернативного (но безумного) плана - но, по сути, CBO должен иметь возможность перемещать это условие.

Вы можете получить желаемый план, использовав фокус с ROWNUM:

scott@ORA920> explain plan for
  2  select ename, dname
  3  from (select * from emp where deptno = 10 and rownum > 0 ) a,
  4       (select * from dept where deptno = 10) b
  5           where a.empno = 7934
  6  /

Explained.

scott@ORA920> select * from table(dbms_xplan.display);

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

---------------------------------------------------------------------
/ Id  / Operation             /  Name       / Rows  / Bytes / Cost  /
---------------------------------------------------------------------
/   0 / SELECT STATEMENT      /             /       /       /       /
/   1 /  NESTED LOOPS         /             /       /       /       /
/*  2 /   TABLE ACCESS FULL   / DEPT        /       /       /       /
/*  3 /   VIEW                /             /       /       /       /
/   4 /    COUNT              /             /       /       /       /
/*  5 /     FILTER            /             /       /       /       /
/*  6 /      TABLE ACCESS FULL/ EMP         /       /       /       /
---------------------------------------------------------------------

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

   2 - filter("DEPT"."DEPTNO"=10)
   3 - filter("A"."EMPNO"=7934)
   5 - filter(ROWNUM>0)
   6 - filter("EMP"."DEPTNO"=10)

Note: rule based optimization

22 rows selected.

но при этом уместно спросить: "Зачем"?

Как заставить работать NO_PUSH_PRED?

У меня есть таблица с миллионами "хороших" строк и несколькими "мусорными". Я пытаюсь отфильтровать плохие записи по представлению даты в VARCHAR2 так, чтобы можно было преобразовать в дату только хорошие записи. Я просто использовал:

SELECT /*+ NO_PUSH_PRED (a) */
       some_columns 
FROM  (
       SELECT some_columns
       FROM   some_table
       WHERE  SUBSTR(char_date_column,1,1) BETWEEN '0' AND '9'
      ) a
,     some_other_table b
WHERE some_join_condition
AND   TO_DATE(a.char_date_column, 'YYYY-MM-DD') < TRUNC(SYSDATE, 'YEAR')

Однако условие проталкивается во вложенное представление "a", поскольку я получаю ошибки в функции TO_DATE для нескольких плохих записей. Если я выношу SUBSTR вне вложенного представления и использую ORDERED_PREDICATES, то все получается. Что посоветуете?

Ответ Тома Кайта

Испольуйте CASE:

where some_join_condition
  and case when substr( char_date_column,1,1) between '0' and '9'
           then to_date( .... )
           else null
       end < trunc( .... ); 

Комметарий к исходному вопросу

Я понимаю, что вы ответили на исходный вопрос более двух лет назад, но мне интересно, помните ли вы, почему условие "group_id = 'TRACE'" (при указании которого индекс использовался) проталкивалось во вложенное представление. Связано ли это с тем, что поле group_id участвовало в аналитической функции, входящей в представление? Не будут ли результаты другими, если вложенное представление сначала строится, а потом к нему применяется условие "group_id = 'TRACE'"? Я собираюсь это проверить, но, к сожалению, сейчас доступа к базе данных у меня нет.

Ответ Тома Кайта

Да, поскольку мы указали столбец group_id в конструкции PARTIONED, условия по group_id можно "безопасно" проталкивать в запрос.

PUSH_PRED и OUTER JOIN

Может ли условие быть протолкнуто в подзапрос, соединяемый с помощью LEFT OUTER JOIN? Например:

SELECT /*+ PUSH_PRED */
FROM SMALL
LEFT JOIN BIG ON SMALL.ID = BIG.ID
WHERE SMALL.ID = 9

Будет ли условие "ID = 9" протолкнуто в подзапрос?

Ответ Тома Кайта

По возможности, да.

... ( Много не особо интересных вопросов пропущено - прим. В.К. )

Фокус с rownum>=0

У меня есть запрос, имеющий удовлетворительную производительность.

Я добавляю к нему условие:

and col1 not like '%something%'

и план запроса полностью меняется, со снижением производительности!

Если я добавлю 'rownum>=0' к существующему запросу, а перед ним еще и мое новое условие, все работает прекрасно. rownum приводит к выполнению внутреннего запроса (с удовлетворительной производительностью) и фильтр применяется только к полученным в результате строкам.

Вопрос: разумно ли добавлять это условие 'rownum>=0' в само представление? Если представление соединяется с другой таблицей, я думаю, это не позволит CBO сгенерировать оптимальный план, поскольку потребует материализовать (построить) представление?

Нет ли других способов добиться того же, что и фокус с 'rownum>=0'?

Ответ Тома Кайта

Добавление такого условия предотвращает слияние представлений и проталкивание услвоий.

Есть подсказки, которые тоже могут предотвратить слияние.

GROUP BY

Как насчет представления/запроса с конструкцией group by?

Когда я выполняю:

select * from (
select col1,col2,sum(col3) group by col1,col2 having count(*)>5
) where col1='foo'

оказывается, что условие col1='foo' проталкивается во внутренний запрос.

Не должна ли конструкция 'having' или даже просто group by предотвращать проталкивание условия?

Ответ Тома Кайта

Нет, не в этом случае, поскольку вы группируете по столбцу col1? - упоминание столбца col1 в конструкции where "безопасно".

Безопасно?

Не уверен, что понял. Так будет условие по столбцу col1 протолкнуто в представление или нет?

Ответ Тома Кайта

Оно может и будет протолкнуто (вы же сами уже это написали?)

А я написал, что это "безопасно", поскольку по этому столбцу выполняется группировка. Происходи полное "слияние" - шага построения представления нет вообще:

ops$tkyte@ORA10GR1> create table t ( c1 int, c2 int, c3 int );

Table created.

ops$tkyte@ORA10GR1> delete from plan_table;

3 rows deleted.

ops$tkyte@ORA10GR1> explain plan for
  2  select *
  3   from (
  4  select c1, c2, sum(c3) from t
  5    group by c1, c2
  6  )
  7  where c1 = 5;
 
Explained.

ops$tkyte@ORA10GR1> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
Plan hash value: 1028120241
 
---------------------------------------------------------------------------
/ Id  / Operation          / Name / Rows  / Bytes / Cost (%CPU)/ Time     /
---------------------------------------------------------------------------
/   0 / SELECT STATEMENT   /      /     1 /    39 /     3  (34)/ 00:00:01 /
/   1 /  SORT GROUP BY     /      /     1 /    39 /     3  (34)/ 00:00:01 /
/*  2 /   TABLE ACCESS FULL/ T    /     1 /    39 /     2   (0)/ 00:00:01 /
---------------------------------------------------------------------------

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

   2 - filter("C1"=5)

Note
-----
   - dynamic sampling used for this statement

18 rows selected.

Статья в Oracle Magazine

В последнем выпуске Oracle Magazine вы объясняли слияние представлений (view merging) и проталкивание условий (predicate pushing). У меня, однако, есть вопрос по слиянию представлений. В одном из ваших примеров (по-моему, в третьем) используется следующее определение представления:

select * from whatever
order by whatever

Вы написали, что из-за конструкции order by слияние этого представления невозможно. Как так? В чем отличие

select * from view where col = 'X'

от

select * 
from (select * from whatever where col = 'X' order by whatever  )

И еще. Что вы имеет ввиду по "СЕМАНТИЧЕСКИМИ" изменениями при указании rownum (для проталкивания условий). Что такое семантика ? Результирующее множество?

Ответ Тома Кайта

Мы не можем преобразовывать:

select * 
  from t1, (select * from t2 order by x) t2
 where t1.y = t2.y
   and t2.z = 5;

в:

select * 
  from t1, t2
 where t1.y = t2.y
   and t2.z = 5 
 order by t2.x;

но мы можем протолкнуть условие во вложенное представление:

select * 
  from t1, (select * from t2 where z = 5 order by x) t2
 where t1.y = t2.y;

Вот что я имел ввиду (учитывайте сложный общий случай, много таблиц, а не одна-две).

Семантика - это "смысл", "ответ". Изменяется ответ на вопрос... А это означает, что "так делать неправильно".

Запросы не будут семантически эквивалентны.

Почему нельзя выполнить слияние?

Я не понимаю, почему нельзя выполнить слияние, преобразовав

select * 
  from t1, (select * from t2 order by x) t2
 where t1.y = t2.y
   and t2.z = 5;

в

select * 
  from t1, t2
 where t1.y = t2.y
   and t2.z = 5 
 order by t2.x;

Пусть у нас есть две следующих таблицы:

t2
x  y  z
-- -- --
3  2  5
1  2  5
2  3  4
4  1  8

t1
y  w
-- --
2  5

Из-за чего семантическая ошибка?

Ответ Тома Кайта

Из-за конструкции order by - order by "по определению" предотвращает слияние.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 17.03.2008 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Oracle Database Standard Edition 2 Processor License
Oracle Database Standard Edition 2 Named User Plus License
Oracle Database Personal Edition Named User Plus License
Oracle Database Personal Edition Named User Plus Software Update License & Support
YourKit Profiler for .NET - Floating License - 1 year of e-mail support and upgrades
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
CASE-технологии
СУБД Oracle "с нуля"
Компьютерные книги. Рецензии и отзывы
Новые материалы
Все о PHP и даже больше
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100