|
|
|||||||||||||||||||||||||||||
|
Проталкивание условия в представлениях, содержащих аналитические функцииИсточник: 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 "по определению" предотвращает слияние. Ссылки по теме
|
|