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

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

Источник: lncom

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

Магазин программного обеспечения   WWW.ITSHOP.RU
Oracle Database Standard Edition 2 Processor License
Oracle Database Personal Edition Named User Plus Software Update License & Support
Oracle Database Standard Edition 2 Named User Plus License
Oracle Database Personal Edition Named User Plus License
Nero 2018 Platinum ESD
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
СУБД Oracle "с нуля"
Новые материалы
Adobe Photoshop: алхимия дизайна
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100