2015-12-28 1 views
-1

J'ai une situation où je suis en train d'exécuter de nombreuses procédures parallèles qui accèdent à la même table. Lorsque j'essaie d'exécuter ces procédures parallèlement, je peux voir que quelques procédures lancent une erreur ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired. Ces tables sont des tables temporaires dans lesquelles je supprime d'abord les anciennes données avant de les insérer. Et encore faire la même chose pour la prochaine procédure. Donc, dans ce cas, j'ai une situation où plusieurs procédures tentent d'accéder à la même table et essaient d'effectuer des opérations DML. Je solution de création de table temporaire globale pour ce cas:Créer une table temporaire globale dans Oracle

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

Mais comme je suis nouveau à cette solution, je ne sais pas vraiment comment cela fonctionne. Par exemple, si une procédure est en cours et tente d'accéder à la table TEMP_ACTIVATE_OPTION pour les opérations DML et qu'une autre procédure s'exécute parallèlement et tente d'accéder à la même table TEMP_ACTIVATE_OPTION pour les opérations DML alors y a-t-il une possibilité de perte de données ou de conflit? Comment les tables temporaires globales gèrent-elles les sessions de transaction? Est-ce qu'il effectue un verrou sur la table si la procédure essaie de faire des opérations dml sur cette table et attend de libérer le verrou sur la table pour qu'une autre procédure puisse accéder à la même table?

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

Est-ce que CAPTURED_DATA_ERROR est une table temporaire? Si non, alors je m'attendrais à ce que la suppression sur cette table soit la cause de l'ORA-00054, pas les tables temporaires (car elles ne causeraient pas cette erreur). Aussi: 'distinct' est *** NON *** une fonction. Cela s'applique toujours aux colonnes ** all ** dans l'instruction 'select'. 'distinct (so.id)' n'a aucun sens. –

+0

Comment peut être supprimer sur CAPTURED_DATA_ERROR crée un problème? Ce n'est pas une table temporaire mais il y a très peu de données. – Andrew

+0

Cela peut arriver lorsqu'une deuxième transaction tente de supprimer les * mêmes * lignes d'une autre transaction (même si je m'attendais à ce que le second attende). –

Répondre

3

Here's the official manual on temporary tables.

La définition d'une table temporaire est visible à toutes les sessions, mais les données dans une table temporaire est visible uniquement à la session que insère les données dans la table.

En bref, vous pouvez penser de table temporaire globale comme si une instance privée de cette table est créé pour votre session lorsque vous accédez à la table. Ce qui se passe réellement à l'intérieur est une autre histoire, mais vous devriez laisser cela à Oracle - ce que vous voyez à votre niveau d'abstraction est une table complètement privée à votre session. Aucune autre session ne peut accéder aux données de votre session dans GTT, et les données sont toujours perdues dès que vous fermez votre session. Aucune autre session ne peut "verrouiller" les lignes de votre session, car elles ne sont pas visibles et aucun conflit ne peut se produire.

Vous devez également différencier les transactions GTT spécifiques aux transactions et aux sessions. ils sont créés en utilisant respectivement ON COMMIT DELETE ROWS et ON COMMIT PRESERVE ROWS, et font exactement ce que ces instructions disent: GTT spécifique à la transaction efface votre table sur chaque COMMIT problème, et spécifique à la session conserve les données jusqu'à la fin de votre session ou vous le supprimez manuellement. Un inconvénient que vous devez savoir est que pour émettre des instructions DDL sauf truncate (alter table, par exemple), vous devrez d'abord tuer toutes les sessions qui utilisent les instances de GTT en premier. Planifiez votre maintenance en conséquence.

+0

Je n'émets aucune instruction ddl, vous pouvez voir dans mon code uniquement l'opération DML que j'effectue. Mais ai-je la confusion que si plusieurs procédures essayent d'accéder à la même table en même temps et exécutent l'opération de DML comme la suppression et l'insèrent alors dans ce cas doi font face à la perte de données? Si une procédure prenait 50sec pour exécuter et terminer l'opération dml sur la table et qu'une autre procédure essayait d'accéder à la même table pour l'opération dml alors dans ce cas comment GTT gère-t-elle cette transaction/session? – Andrew

+0

Lorsque vous travaillez avec GTT, vous ne vous souciez pas de ce que font les autres sessions, parce que vous avez votre propre instance. Les autres sessions ne peuvent pas accéder à vos données, elles ne peuvent pas les lire, elles ne peuvent pas les supprimer, tout est à vous. Comment voulez-vous que la perte de données se produise exactement? Je ne comprends pas de quoi vous parlez avec une «telle» transaction. – Timekiller

+0

Je veux dire par exemple que ma procédure exécute l'opération DML sur la table afin qu'elle ait une session et qu'une autre procédure essaye d'exécuter l'opération dml sur la même table en même temps alors elle a aussi sa propre session. Donc, si ces 2 sessions se déroulent en même temps, que va-t-il se passer? – Andrew