Параллельное выполнение процедур в операторе SQL (Oracle 11g)

У меня есть SQL-оператор, в котором используется Check-Function, выполнение которого занимает довольно много времени.

Теперь я хочу распараллелить выполнение Check-Function, но это не работает.

Где ошибка, которую я сделал?

Пример ниже выполняется за 5 секунд, но, насколько я понимаю, это должно занять около 1 секунды из-за параллелизма.

Фрагмент кода для тестирования:

CREATE TABLE PERSON AS
SELECT LEVEL AS ID, 'Person_'||LEVEL AS NAME
FROM DUAL 
CONNECT BY LEVEL <= 5;

CREATE OR REPLACE FUNCTION LONGCHECKFUNC(ID NUMBER)
RETURN NUMBER IS
BEGIN
    --Doing some very heavy Checks....
    DBMS_LOCK.SLEEP(1 /*second*/);
    RETURN 1;
END;

SELECT /*+PARALLEL(person, 5) */ *
 FROM PERSON
WHERE LONGCHECKFUNC(ID)=1;

person bernhard.weingartner    schedule 19.11.2012    source источник
comment
Итак, вы хотели бы иметь какое-то асинхронное выполнение процедур? Параллельное выполнение нескольких процедур одновременно?   -  person Jacob    schedule 19.11.2012
comment
Это правильно. Я хочу выполнить одну и ту же процедуру (LongCheckFunc) для каждой строки одновременно.   -  person bernhard.weingartner    schedule 19.11.2012
comment
Взгляните на это, может оказаться полезным   -  person Jacob    schedule 19.11.2012


Ответы (2)


CREATE TABLE PERSON
PARTITION BY HASH(ID) PARTITIONS 16 /* <-- ADDED*/
AS
SELECT LEVEL AS ID, 'Person_'||LEVEL AS NAME
FROM DUAL 
CONNECT BY LEVEL <= 5;

CREATE OR REPLACE FUNCTION LONGCHECKFUNC(ID NUMBER)
RETURN NUMBER PARALLEL_ENABLE /* <-- ADDED*/ IS
BEGIN
    --Doing some very heavy Checks....
    DBMS_LOCK.SLEEP(1 /*second*/);
    RETURN 1;
END;
/

SELECT /*+PARALLEL(person, 5) */ *
 FROM PERSON
WHERE LONGCHECKFUNC(ID)=1;

Во-первых, вам нужно добавить PARALLEL_ENABLE в свой функция. Это сообщает Oracle, что вызовы функций не совместно используют какие-либо данные сеанса и могут выполняться независимо.

Второе изменение, добавление разбиения по хешу, я не совсем понимаю. Это зависит от внутренних алгоритмов, которые Oracle использует для разделения рабочих нагрузок. При наличии хеш-разделов проще всего разделить сегменты между параллельными серверами. Без секционирования имеется лишь небольшое количество блоков, и Oracle, вероятно, полагает, что будет быстрее всего выполнять все на одном параллельном сервере.

(Даже если вы используете ASSOCIATE STATISTICS и даете функции смешную стоимость, Oracle все равно будет запускать ее последовательно. Возможно, есть какое-то ограничение, из-за которого Oracle никогда не будет разделять блок между несколькими параллельными серверами?)

Это работает примерно в 1.1. секунд на моей машине. Но поскольку это зависит от (AFAIK) недокументированного поведения, я не уверен, что оно будет работать так же для вас. Хеш-функции Oracle не помещают значения в сегменты простым циклическим способом. Чтобы свести к минимуму коллизии и повысить вероятность оптимального параллелизма, вам потребуется использовать большое количество разделов.

Как упомянул @David Aldridge, параллельный запрос на самом деле не предназначен для этого. Если вам нужен более детерминированный процесс, вам понадобится что-то вроде решения, предложенного @Polppan (используйте DBMS_SCHEDULER).

person Jon Heller    schedule 20.11.2012
comment
Большое спасибо, это именно то решение, которое я хочу. Это работает для меня отлично! - person bernhard.weingartner; 20.11.2012

Параллельный запрос не предназначен для такой функциональности.

Лучшим способом действий здесь было бы начать настройку самой функции.

person David Aldridge    schedule 19.11.2012