2015-12-28 5 views
-1

У меня есть ситуация, когда я выполняю несколько параллельных процедур, которые обращаются к одной и той же таблице. Когда я пытаюсь выполнить эти процедуры параллельно, я вижу, что некоторые из процедур вызывают ошибку ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired. Эти таблицы являются временными таблицами, в которых я сначала удаляю старые данные, а затем вставляю их. И снова сделать то же самое для следующей процедуры. Поэтому в этом случае у меня есть ситуация, когда несколько процедур пытаются получить доступ к одной таблице и попытаться выполнить операции DML. У меня есть решение создания глобальной временной таблицы для этого случая:Создать глобальную временную таблицу в oracle

CRATE GLOBAL TEMPORARY TABLE TEMP_ACTIVATE_OPTION(
    ID NUMBER, 
    ... -- your columns 
) 
ON COMMIT DELETE ROWS; 

Но, как я новичок в этом решении я действительно не знаю, как это работает. Например, если выполняется процедура и пытается получить доступ к таблице TEMP_ACTIVATE_OPTION для операций DML, а другая процедура выполняется параллельно и пытается получить доступ к той же таблице TEMP_ACTIVATE_OPTION для операций DML, то в этом есть возможность потери или конфликта данных? Как глобальные временные таблицы управляют сеансами транзакции? Выполняет ли это блокировку на таблице, если процедура пытается выполнить операции dml в этой таблице, и она ожидает освобождения блокировки таблицы, чтобы другая процедура могла получить доступ к одной и той же таблице?

PROCEDURE     "EXT_10024_ACTIVATE_OPTION"(IN_KPI_DEF_ID IN NUMBER DEFAULT 0) AS 

IN_EVENT_ID NUMBER; 
err_code VARCHAR(100); 
err_msg VARCHAR(100); 
IN_OBJECT_NAME VARCHAR2(100); 

CURSOR KPI_DEF_CUR IS 
Select KPI_DEF_ID,BUSINESS_CHECK_PERIOD_ID,BUS_CHK_PRD_ID_1, 
CASE WHEN BUSINESS_CHECK_PERIOD_UNIT_ID=11 THEN 'MINUTE' 
WHEN BUSINESS_CHECK_PERIOD_UNIT_ID=12 THEN 'HOUR' 
WHEN BUSINESS_CHECK_PERIOD_UNIT_ID=13 THEN 'DAY' 
WHEN BUSINESS_CHECK_PERIOD_UNIT_ID IS NULL THEN 'MINUTE' 
END AS BUSINESS_CHECK_PERIOD_UNIT_ID, 
CASE WHEN BUSINESS_CHK_PERIOD_VAL IS NULL THEN 0 
ELSE BUSINESS_CHK_PERIOD_VAL END AS BUSINESS_CHK_PERIOD_VAL, 
CASE WHEN BUS_CHK_PRD_UNIT_ID_1=11 THEN 'MINUTE' 
WHEN BUS_CHK_PRD_UNIT_ID_1=12 THEN 'HOUR' 
WHEN BUS_CHK_PRD_UNIT_ID_1=13 THEN 'DAY' 
WHEN BUS_CHK_PRD_UNIT_ID_1 IS NULL THEN 'MINUTE' 
END AS BUS_CHK_PRD_UNIT_ID_1, 
CASE WHEN BUS_CHK_PRD_VAL_1 IS NULL THEN 0 
ELSE BUS_CHK_PRD_VAL_1 END AS BUS_CHK_PRD_VAL_1, 
EVENT_ID FROM RATOR_MONITORING_CONFIGURATION.KPI_DEFINITION where KPI_DEF_ID = IN_KPI_DEF_ID; 

BEGIN 

--delete the data from TEMP_SERVICE_OPTION and TEMP_SERVICE_OPTION_EXTRACTION 
Delete from TEMP_ACTIVATE_OPTION; 
Delete from TEMP_SERVICE_OPTION_EXTRACTION; 
Delete from TEMP_SERVICE_OPTION; 

DELETE FROM CAPTURED_DATA_ERROR WHERE EVENT_TIMESTAMP < SYSDATE - 60 and EVENT_ID=10024; 

-- removed, retrieve a new START_ID from source first, don't use the last id. 
-- SELECT LAST_TASK_ID INTO LAST_SO_ID FROM CAPTURING where DB_TABLE='TEMP_SERVICE_OPTION'; 
--SELECT MIN(SO.ID) INTO LAST_SO_ID FROM [email protected]_RETAIL SO WHERE SO.ID >= to_char(SYSDATE -1, 'YYYYMMDDHH24MISS')||'0000'; 

Select EVENT_ID INTO IN_EVENT_ID FROM RATOR_MONITORING_CONFIGURATION.KPI_DEFINITION where KPI_DEF_ID = IN_KPI_DEF_ID; 

FOR KPI_DEF_ROW IN KPI_DEF_CUR 
LOOP 

BEGIN 
INSERT INTO TEMP_ACTIVATE_OPTION(ID,ICC,ASSIGNED_ANUMBER_ID,SERVICE_ID,PRODUCT_OPTION_ID,STATUS_ID,END_DATE,PRODUCT_TYPE_KEY) 
Select DISTINCT(SO.ID),SIM.ICC,SIM.ASSIGNED_ANUMBER_ID,SO.SERVICE_ID,SO.PRODUCT_OPTION_ID,SO.STATUS_ID,SO.END_DATE,SIM.PRODUCT_TYPE_KEY FROM 
[email protected]_RETAIL SIM 
    JOIN [email protected]_RETAIL SO ON SO.SERVICE_ID=SIM.ASSIGNED_TO_SERVICE_ID 
where SO.STATUS_ID IN (20,40) 
and SO.ID < to_char(SYSDATE - numtodsinterval ( KPI_DEF_ROW.BUSINESS_CHK_PERIOD_VAL,KPI_DEF_ROW.BUSINESS_CHECK_PERIOD_UNIT_ID), 'YYYYMMDDHH24MISS')||'0000' 
and SO.ID > to_char(SYSDATE - numtodsinterval (KPI_DEF_ROW.BUS_CHK_PRD_VAL_1, KPI_DEF_ROW.BUS_CHK_PRD_UNIT_ID_1), 'YYYYMMDDHH24MISS')||'0000' 
and NOT EXISTS(SELECT ID from TEMP_ACTIVATE_OPTION T WHERE T.ID = SO.ID); 

EXCEPTION WHEN NO_DATA_FOUND THEN 
DBMS_OUTPUT.PUT_LINE('NO_DATA_FOUND exception in EXT_10024_ACTIVATE_OPTION - KPI_DEF_ID:'||to_char(IN_KPI_DEF_ID)); 
RAISE; 

END; 

commit; 

BEGIN 
INSERT INTO TEMP_SERVICE_OPTION_EXTRACTION(ID,ICC,ASSIGNED_ANUMBER_ID,SERVICE_ID,PRODUCT_OPTION_ID,STATUS_ID,END_DATE,A_NUMBER,PRODUCT_TYPE_KEY) 
Select DISTINCT(SO.ID),SO.ICC,SO.ASSIGNED_ANUMBER_ID,SO.SERVICE_ID,SO.PRODUCT_OPTION_ID,SO.STATUS_ID,SO.END_DATE,AN.A_NUMBER,SO.PRODUCT_TYPE_KEY FROM 
TEMP_ACTIVATE_OPTION SO JOIN 
[email protected]_RETAIL PO ON SO.PRODUCT_OPTION_ID = PO.ID JOIN 
[email protected]_RETAIL PC ON PO.OPTION_KEY=PC.DEFAULT_PRODUCT_OPTIONS 
JOIN [email protected]_RETAIL PT ON PC.ID = PT.PRODUCT_CONFIG_ID 
JOIN TEMP_ACTIVATE_OPTION SO ON SO.PRODUCT_TYPE_KEY=PT.KEY 
JOIN 
[email protected]_RETAIL AN ON SO.ASSIGNED_ANUMBER_ID = AN.ID 
where SO.STATUS_ID IN (20,40) 
and NOT EXISTS(SELECT ID from TEMP_SERVICE_OPTION_EXTRACTION T WHERE T.ID = SO.ID); 

EXCEPTION WHEN NO_DATA_FOUND THEN 
DBMS_OUTPUT.PUT_LINE('NO_DATA_FOUND exception in EXT_10024_ACTIVATE_OPTION - KPI_DEF_ID:'||to_char(IN_KPI_DEF_ID)); 
RAISE; 

END; 

commit; 

BEGIN 
--SELF_REGISTRATION ACTIVATE OPTION 
INSERT INTO TEMP_SERVICE_OPTION(ID,SERVICE_ID,PRODUCT_OPTION_ID,STATUS_ID,EVENT_TIMESTAMP,END_DATE,EVENT_ID,SUBSCRIPTION_ID,ORDER_NUMBER,A_NUMBER) 
Select DISTINCT(SO.ID),SO.SERVICE_ID,SO.PRODUCT_OPTION_ID,SO.STATUS_ID,to_date(substr(SO.ID, 1, 14), 'YYYYMMDDHH24MISS'),SO.END_DATE, 
IN_EVENT_ID 
,TSM.SUBSCRIPTION_ID,TSM.ORDER_NUMBER,SO.A_NUMBER 
from TEMP_SERVICE_OPTION_EXTRACTION SO JOIN TMP_SOAP_MONITORING_IDS TSM 
ON SO.A_NUMBER = TSM.MSISDN 
where SO.STATUS_ID IN (20,40) and TSM.ORDER_TYPE='SELF_REGISTRATION' and 
TSM.CREATE_DATE < SYSDATE - numtodsinterval ( KPI_DEF_ROW.BUSINESS_CHK_PERIOD_VAL,KPI_DEF_ROW.BUSINESS_CHECK_PERIOD_UNIT_ID) 
and TSM.CREATE_DATE > SYSDATE - numtodsinterval (KPI_DEF_ROW.BUS_CHK_PRD_VAL_1, KPI_DEF_ROW.BUS_CHK_PRD_UNIT_ID_1) 
and NOT EXISTS(SELECT ID from TEMP_SERVICE_OPTION T WHERE T.ID = SO.ID) 
and TSM.WEB_SERVICE_NAME ='RatorWebShopService' and TSM.WEB_METHOD_NAME ='placeShopOrder'; 

EXCEPTION WHEN NO_DATA_FOUND THEN 
DBMS_OUTPUT.PUT_LINE('NO_DATA_FOUND exception in EXT_10024_ACTIVATE_OPTION - KPI_DEF_ID:'||to_char(IN_KPI_DEF_ID)); 
RAISE; 

END; 

END LOOP; 

commit; 

--INSERT TEMP DATA INTO CAPTURED_DATA_01 TABLE 
Insert into CAPTURED_DATA_01(SUBSCRIPTION_ID,ENV_ID,BRAND_ID,BP_ID,EVENT_ID,ORDER_ID,STATUS_DESCRIPTION,STATUS_CODE,EVENT_TIMESTAMP) 
Select DISTINCT(DCR.SUBSCRIPTION_ID),BBE.ENV_ID,TSM.BRAND_ID,BBE.BP_ID,DCR.EVENT_ID, 
DCR.ORDER_NUMBER, 
CASE WHEN DCR.STATUS_ID=20 THEN 'OK' 
WHEN DCR.STATUS_ID=40 THEN 'ERROR' 
END,DCR.STATUS_ID, 
DCR.EVENT_TIMESTAMP from TEMP_SERVICE_OPTION DCR JOIN TMP_SOAP_MONITORING_IDS TSM ON TSM.SUBSCRIPTION_ID=DCR.SUBSCRIPTION_ID 
JOIN 
RATOR_MONITORING_CONFIGURATION.ENV_BRAND_BP_EVENT BBE ON BBE.EVENT_ID = DCR.EVENT_ID JOIN 
RATOR_MONITORING_CONFIGURATION.ENVIRONMENT ENV on BBE.ENV_ID=ENV.ENV_ID 
JOIN RATOR_MONITORING_CONFIGURATION.BRAND BR ON BBE.BRAND_ID = BR.BRAND_ID 
JOIN RATOR_MONITORING_CONFIGURATION.BUSINESS_PROCESS BP ON BBE.BP_ID = BP.BP_ID 
AND NOT EXISTS(SELECT CD.SUBSCRIPTION_ID FROM CAPTURED_DATA_01 CD WHERE CD.EVENT_ID = DCR.EVENT_ID AND CD.SUBSCRIPTION_ID = DCR.SUBSCRIPTION_ID); 

EXCEPTION WHEN OTHERS THEN 
err_code := SQLCODE; 
err_msg := SUBSTR(SQLERRM, 1, 200); 

DBMS_OUTPUT.PUT_LINE('OTHERS exception in EXT_10072_REQ_SENT_SPAIN - KPI_DEF_ID:'||to_char(IN_KPI_DEF_ID) || err_code || '----' || err_msg || 'OBJECT_NAME->'); 
RAISE; 

COMMIT; 


END EXT_10024_ACTIVATE_OPTION; 
+0

Является ли 'CAPTURED_DATA_ERROR' временной таблицей? Если нет, то я ожидаю, что удаление в этой таблице будет причиной ORA-00054, а не временными таблицами (так как они не вызовут этой ошибки). Также: 'distinct' *** *** *** функция. Он всегда применяется к ** всем ** столбцам в инструкции 'select'. 'distinct (so.id)' не имеет смысла. –

+0

Как удалить объект CAPTURED_DATA_ERROR создает проблему? Это не временная таблица, но она содержит очень мало данных. – Andrew

+0

Это может произойти, когда вторая транзакция пытается удалить * те же * строки, что и другая транзакция (хотя я ожидал, что второй будет ждать). –

ответ

3

Here's the official manual on temporary tables.

Определения временной таблицы видна все сеансы, но данных во временной таблице видны только сессию, вставляет данные в таблицу.

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

Никакая другая сессия не может получить доступ к данным, которые имеет ваша сессия в GTT, и данные всегда теряются, как только вы закрываете сеанс. Никакая другая сессия не может «блокировать» строки в вашей сессии, так как они не видны и конфликтов не происходит.

Вы также должны различать GTT для транзакций и сеансов. они создаются с использованием ON COMMIT DELETE ROWS и ON COMMIT PRESERVE ROWS соответственно и делают то, что говорят эти инструкции: GTT, специфичный для транзакций, очищает вашу таблицу на каждом COMMIT, который вы выдаете, и зависит от конкретного сеанса, до тех пор, пока ваш сеанс не закончится или вы не удалите его вручную.

Один недостаток, который вы должны знать, заключается в том, что для выдачи операторов DDL, кроме truncate (например, alter table), вам придется сначала убить все сеансы, которые используют экземпляры упомянутого GTT. Планируйте свое обслуживание соответственно.

+0

Я не выдаю никакой инструкции ddl, вы можете видеть в моем коде свою только операцию DML, которую я выполняю. Но у меня есть путаница в том, что если несколько процедур попытаются получить доступ к одной и той же таблице одновременно и выполнить операцию DML, например delete, а затем вставить, то в этом случае doi сталкивается с проблемой потери данных? Если одна процедура заняла 50 секунд для запуска и завершения операции dml в таблице, а другая процедура пытается получить доступ к той же таблице для операции dml, то в этом случае, как GTT обрабатывает такую ​​транзакцию/сеанс? – Andrew

+0

При работе с GTT вам все равно, какие другие сеансы работают с ним, потому что у вас есть свой собственный экземпляр. Другие сеансы не могут получить доступ к вашим данным, они не могут его прочитать, они не могут удалить его, это все ваше. Как бы вы ожидали, что потеря данных произойдет именно? Я не понимаю, что вы имеете в виду с такой транзакцией. – Timekiller

+0

Я хочу сказать, например, моя процедура выполняет операцию DML в таблице, поэтому у нее есть сценарий, а другая процедура пытается одновременно выполнить операцию dml в той же таблице, тогда она также имеет свой собственный сеанс. Итак, если эти 2 сеанса одновременно ругаются, что произойдет? – Andrew

Смежные вопросы