为什么会失败?
Why is this failing?
我正在绞尽脑汁想弄清楚这个查询有什么问题。
EXECUTE IMMEDIATE '
INSERT INTO ORDERS_HISTORY@' || DBLINK || '
(ID, ITEM_ID, ITEM_DESC, QUANTITY, INSERTED_ON, INSERTED_BY)
SELECT A.ORDER_ID, A.ITEM_ID, A.ITEM_DESC, A.QUANTITY_SOLD, SYSDATE, ''' || OS_USER || '''
FROM ORDERS@' || DBLINK || ' A, ORDERS@APOLLO B
WHERE A.ORDER_ID = B.ORDER_ID AND (B.INSERTED_ON >= ''' || V_DATE || ''' OR B.UPDATED_ON >= ''' || V_DATE || ''')';
此查询是我正在开发的程序的一部分,用于跟踪远程 ORDERS table 中的更改,"synchronizing" 它与另一台服务器上的 ORDERS table 并保存更改后者在 ORDERS_HISTORY table。因此,ORDERS@APOLLO 应该始终与 ORDERS@' || DBLINK || '
同步(DB_LINK 是动态的,因为在多个服务器上应该 运行),而更改存储在 ORDERS_HISTORY@' || DBLINK || '
table。两个数据库 运行 Oracle 11g.
简而言之,源table在服务器A,代码运行在服务器B,目标table存放在服务器C,A不能"talk" 到 C,所以这是我能想到的最好的。
如果我 "test run" 它没有动态 sql 它工作正常,即它插入预期的行数 (250)。但是,当我 运行 过程,并且查询是 运行 并立即执行时,它会插入超过 160k(16 万!!!)行。
有什么问题吗?
提前致谢!
编辑: V_DATE 定义为:
SELECT TO_DATE('01/01/2010 00:00:00', 'DD/MM/YYYY HH24:MI:SS') INTO V_DATE FROM DUAL;
编辑 2: 从插入字段列表中删除 SYSDATE 将行数减少了大约一半(大约 80k)。还是太多了,但这是一个开始。
在构建 SQL 字符串的这一部分中,您依赖于日期到字符串的隐式类型转换。
(B.INSERTED_ON >= ''' || V_DATE || ''' OR B.UPDATED_ON >= ''' || V_DATE || ''')
这意味着该行为取决于会话的当前 NLS_DATE_FORMAT 以及与结果字符串进行比较的列的数据类型。当您以交互方式测试查询时,您可能正在以一种恰好有效的格式手动输入日期字符串。
我不确定这是否是问题所在,但我认为您应该消除它作为可能的麻烦源。
一种方法是确保转换在两个方向上都是明确的。例如,假设 INSERTED_ON
是一个日期,执行如下操作:
'B.INSERTED_ON >= TO_DATE(''' || TO_CHAR( v_date, 'YYYYMMDD' ) || ''', ''YYYMMDD'')'
另一种方法,当然可以使代码更具可读性并且在其他方面可能更好,是使用绑定变量:
'B.INSERTED_ON >= :bind_date'
在 EXECUTE
语句的末尾添加一个 USING
子句以提供将绑定的值:
USING v_date
我正在绞尽脑汁想弄清楚这个查询有什么问题。
EXECUTE IMMEDIATE '
INSERT INTO ORDERS_HISTORY@' || DBLINK || '
(ID, ITEM_ID, ITEM_DESC, QUANTITY, INSERTED_ON, INSERTED_BY)
SELECT A.ORDER_ID, A.ITEM_ID, A.ITEM_DESC, A.QUANTITY_SOLD, SYSDATE, ''' || OS_USER || '''
FROM ORDERS@' || DBLINK || ' A, ORDERS@APOLLO B
WHERE A.ORDER_ID = B.ORDER_ID AND (B.INSERTED_ON >= ''' || V_DATE || ''' OR B.UPDATED_ON >= ''' || V_DATE || ''')';
此查询是我正在开发的程序的一部分,用于跟踪远程 ORDERS table 中的更改,"synchronizing" 它与另一台服务器上的 ORDERS table 并保存更改后者在 ORDERS_HISTORY table。因此,ORDERS@APOLLO 应该始终与 ORDERS@' || DBLINK || '
同步(DB_LINK 是动态的,因为在多个服务器上应该 运行),而更改存储在 ORDERS_HISTORY@' || DBLINK || '
table。两个数据库 运行 Oracle 11g.
简而言之,源table在服务器A,代码运行在服务器B,目标table存放在服务器C,A不能"talk" 到 C,所以这是我能想到的最好的。
如果我 "test run" 它没有动态 sql 它工作正常,即它插入预期的行数 (250)。但是,当我 运行 过程,并且查询是 运行 并立即执行时,它会插入超过 160k(16 万!!!)行。
有什么问题吗?
提前致谢!
编辑: V_DATE 定义为:
SELECT TO_DATE('01/01/2010 00:00:00', 'DD/MM/YYYY HH24:MI:SS') INTO V_DATE FROM DUAL;
编辑 2: 从插入字段列表中删除 SYSDATE 将行数减少了大约一半(大约 80k)。还是太多了,但这是一个开始。
在构建 SQL 字符串的这一部分中,您依赖于日期到字符串的隐式类型转换。
(B.INSERTED_ON >= ''' || V_DATE || ''' OR B.UPDATED_ON >= ''' || V_DATE || ''')
这意味着该行为取决于会话的当前 NLS_DATE_FORMAT 以及与结果字符串进行比较的列的数据类型。当您以交互方式测试查询时,您可能正在以一种恰好有效的格式手动输入日期字符串。
我不确定这是否是问题所在,但我认为您应该消除它作为可能的麻烦源。
一种方法是确保转换在两个方向上都是明确的。例如,假设 INSERTED_ON
是一个日期,执行如下操作:
'B.INSERTED_ON >= TO_DATE(''' || TO_CHAR( v_date, 'YYYYMMDD' ) || ''', ''YYYMMDD'')'
另一种方法,当然可以使代码更具可读性并且在其他方面可能更好,是使用绑定变量:
'B.INSERTED_ON >= :bind_date'
在 EXECUTE
语句的末尾添加一个 USING
子句以提供将绑定的值:
USING v_date