SELECT * FROM TABLE (конвейерна функция): мога ли да съм сигурен в реда на редовете в резултата?

В следващия пример винаги ли ще получавам „1, 2“ или е възможно да получа „2, 1“ и можете ли да ми кажете къде в документацията виждате тази гаранция, ако съществува?

Ако отговорът е да, това означава, че без ORDER BY или ORDER SIBLINGS има начин да сте сигурни в реда на набора от резултати в оператор SELECT.

CREATE TYPE temp_row IS OBJECT(x number);
/

CREATE TYPE temp_table IS TABLE OF temp_row;
/

CREATE FUNCTION temp_func
RETURN temp_table PIPELINED
IS
BEGIN
    PIPE ROW(temp_row(1));
    PIPE ROW(temp_row(2));
END;
/

SELECT * FROM table(temp_func());

Благодаря ти.


person Benoit    schedule 23.05.2013    source източник
comment
:Да, ако обърнете реда на PIPE ROW, тогава ще ви даде изход 2,1, в противен случай 1,2. И ако искате това за конкретна поръчка, тогава добавете клауза за ред във вашата заявка за избор. В противен случай заявката за избор ще върне данните въз основа на последователността PIPE ROW   -  person Gaurav Soni    schedule 23.05.2013


Отговори (3)


Не мисля, че има някъде в документацията, която гарантира реда, в който данните ще бъдат върнати.

Има един стар Тема на Tom Kyte от 2003 г. (така че може да е остаряла), която гласи, че разчитането на имплицитния ред не би било препоръчително поради същите причини, по които не бихте разчитали на реда в обикновен SQL.

1-во: редът на редовете, върнати от функцията на таблицата в рамките на SQL оператор, същият ли е редът, в който записите са били "предадени" във вътрешната колекция (така че не е необходим ред по клауза)?

...

Продължение 18 май 2003 г. - 10 сутринта UTC:

1) може би, може би не, не бих разчитал на това. Не трябва да разчитате на реда на редовете в набор от резултати, без да имате ред по. Ако се присъедините или направите нещо по-сложно, тогава просто "изберете * от таблица( f(x))", редовете може да се върнат в друг ред.

емпирично - изглежда, че се връщат, когато бъдат предадени. Не вярвам да е документирано, че това е така.

Всъщност колекциите от тип NESTED TABLE са документирани, че изрично нямат способността да запазват реда.

За да сте сигурни, трябва да направите както винаги в заявка, да посочите изрично ORDER BY, ако искате резултатите от заявката да са подредени.

След като казах, че взех вашата функция и изпълних 10 милиона итерации, за да проверя дали имплицитният ред някога е бил нарушен; не беше.

SQL> begin
  2    for i in 1 .. 10000000 loop
  3      for j in ( SELECT a.*, rownum as rnum FROM table(temp_func()) a ) loop
  4
  5         if j.x <> j.rnum then
  6            raise_application_error(-20000,'It broke');
  7         end if;
  8      end loop;
  9    end loop;
 10  end;
 11  /

PL/SQL procedure successfully completed.
person Ben    schedule 23.05.2013
comment
Благодаря ви за този отговор, този отговор от 2003 г. на Том Кайт е наистина интересен. - person Benoit; 23.05.2013

Тази процедурна логика работи по различен начин спрямо базираните на таблици заявки. Причината, поради която не можете да разчитате на поръчки в избор от таблица, е, че не можете да разчитате на реда, в който RDBMS ще идентифицира редовете като част от необходимия набор. Това отчасти се дължи на промяната на плановете за изпълнение и отчасти защото има много малко ситуации, в които физическият ред на редовете в таблица е предвидим.

Тук обаче избирате от функция, която гарантира реда, в който се излъчват редовете от функцията. При отсъствието на съединения, агрегации или почти всичко друго (т.е. за директен „избор ... от таблица(функция)“) бих бил доста сигурен, че редът на редовете е детерминистичен.

Този съвет не се прилага, когато има включена таблица, освен ако няма изрично подреждане по, така че ако заредите вашата pl/sql колекция от заявка, която не използва подреждане по, тогава, разбира се, редът на редовете в колекцията не е детерминистично.

person David Aldridge    schedule 23.05.2013

Връзката към AskTom в приетия отговор е повредена в момента, но намерих по-нов, но много подобен въпрос. След известен пинг-понг на недоразумения, Конър Макдоналд най-накрая признава, че подреждането е стабилно при определени условия, включващи паралелизъм и референтни курсори и свързани само с текущи версии. Цитат:

Паралелизмът е (потенциалният) риск тук. Както в момента стои, конвейерна функция може да се изпълнява паралелно само ако приема референтен курсор като вход. Разбира се, няма гаранция, че това няма да се промени в бъдеще. Така че бихте могли да работите с предположението, че в настоящите версии ще върнете редовете в ред, но никога не бихте могли да разчитате на 100%, че това е така сега и завинаги .

Така че не се дава гаранция за бъдещи версии.

Въпросната функция ще премине този критерий, следователно трябва да осигури стабилно подреждане. Въпреки това, аз лично не бих се доверил. Моят случай (когато открих този въпрос) беше дори по-прост: избиране от колекция, посочено буквално - select column_value from table(my_collection(5,3,7,2)) и така или иначе предпочетох изрично сдвояване между данни и индекс. Не е толкова трудно и не е много по-дълго.

Oracle трябва да научи от Postgres къде тази ситуация се решава от unnest(array) with ordinality, което е ясно разбираема, надеждна и добре документирана функция.

person Tomáš Záluský    schedule 11.11.2020