Проштовхування умови в уявленнях, що містять аналітичні функції, Інші СУБД, Бази даних, статті

У мене в базі даних є уявлення, що містить аналітичну функцію. Аналітична функція проходить вікном по набору рядків таблиці і повертає їх підмножина. Початкове тестування використання цього подання дало дуже багатообіцяючі результати, оскільки при використанні аналітичної функції серверу для отримання відповіді потрібно виконати НАБАГАТО менше дій, ніж при з’єднанні таблиці з самою собою (раніше використовувався такий підхід). При цьому використовувалися запити до подання, що відбирають дані по тому ж стовпцю, за яким виконувалося секціонування таблиці в аналітичній функції. Однак, коли в запиті до подання я задав умова по іншому стовпцю в конструкції 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 byorder by “За визначенням” запобігає злиття.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*