在 oracle 中创建全局临时 table

Create global temporary table in oracle

我遇到的情况是 运行 并行访问同一个 table 的许多程序。当我尝试 运行 并行执行这些程序时,我可以看到很少有程序会抛出错误 ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired。那些 tables 是临时的 tables,我先删除旧数据然后插入。并为下一个程序再次做同样的事情 运行。所以在这种情况下,我遇到了多个过程尝试访问相同的 table 并尝试执行 DML 操作的情况。对于这种情况,我有创建全局临时 table 的解决方案:

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

但是由于我是这个解决方案的新手,所以我真的不知道它是如何工作的。例如,如果一个过程 运行ning 并试图访问 table TEMP_ACTIVATE_OPTION 进行 DML 操作,而另一个过程 运行s 并行并试图访问相同的 table TEMP_ACTIVATE_OPTION 对于 DML 操作,那么这里是否存在数据丢失或冲突的可能性?全局临时 table 如何管理会话或事务?如果程序尝试在 table 上执行 dml 操作,它是否在 table 上执行锁定,它等待释放 table 上的锁,以便另一个程序可以访问相同的 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 SERVICE_OPTION@FONIC_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
SIMCARD@FONIC_RETAIL SIM
  JOIN SERVICE_OPTION@FONIC_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
PRODUCT_OPTION@FONIC_RETAIL PO ON SO.PRODUCT_OPTION_ID = PO.ID JOIN
PRODUCT_CONFIG@FONIC_RETAIL PC ON PO.OPTION_KEY=PC.DEFAULT_PRODUCT_OPTIONS
JOIN PRODUCT_TYPE@FONIC_RETAIL PT ON PC.ID = PT.PRODUCT_CONFIG_ID
JOIN TEMP_ACTIVATE_OPTION SO ON SO.PRODUCT_TYPE_KEY=PT.KEY
JOIN
A_NUMBER@FONIC_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;

Here's the official manual on temporary tables.

The definition of a temporary table is visible to all sessions, but the data in a temporary table is visible only to the session that inserts the data into the table.

简而言之,您可以认为 全局临时 table 就好像 私有实例 table 是在您首次访问 table 时为您的会话创建的。内部实际发生的情况是另一回事,但您应该将其留给 Oracle - 您在抽象级别看到的是 table 完全私有的会话。

没有其他会话可以访问您的会话在 GTT 中的数据,并且一旦您关闭会话,数据总是会丢失。没有其他会话可以在您的会话中 "lock" 行,因为它们是不可见的,并且不会发生冲突。

您还应该区分特定于交易和会话的 GTT。它们是分别使用 ON COMMIT DELETE ROWSON COMMIT PRESERVE ROWS 创建的,并且完全按照这些说明进行操作:特定于交易的 GTT 在您发出的每个 COMMIT 上清除您的 table,并且特定于会话保留数据直到您的会话结束或您手动删除它。

您应该注意的一个缺点是,要发出除截断之外的 DDL 语句(例如,更改 table),您必须首先终止所有正在使用所述 GTT 实例的会话。相应地计划您的维护。