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