如何有效地从 SAS 更新 Oracle Table?

How to update an Oracle Table from SAS efficiently?

我要解决的问题:

我有一个 SAS 数据集 work.testData(在工作库中),它包含 8 列和大约 100 万行。所有列都是文本(即没有数字数据)。此 SAS 数据集的文件大小约为 100 MB。我的 objective 是有一个步骤将整个 SAS 数据集解析到 Oracle 中。即有点像从 SAS 平台到 Oracle 平台的 SAS 数据集的 "copy and paste"。这背后的基本原理是,每天,Oracle 中的这个 table 都会被 SAS 中的 "replaced" 获取,这将启用下游 Oracle 进程。

我的解决方法:

Oracle 中的一次性初始设置:

  1. 在 Oracle 中,我创建了一个名为 testData 的 table,其 table 结构与 SAS 数据集 testData 几乎相同。 (即相同的 table 名称、相同的列数、相同的列名等)。

正在进行的重复过程:

  1. 在 SAS 中,执行 SQL-传递到 t运行cate ora.testData(即删除所有行,同时保留 table 结构)。这确保 ora.testData 在从 SAS 插入之前为空。
  2. 在 SAS 中,LIBNAME 语句将 Oracle 数据库指定为 SAS 库(称为 ora)。所以我可以 "see" Oracle 中的内容并从 SAS 中执行 read/update。
  3. 在 SAS 中,PROC SQL 过程将来自 SAS 数据集 work.testData 的数据 "insert" 导入 Oracle table ora.testData.

示例代码

Oracle 中的一次性初始设置:

第 1 步:运行 Oracle SQL Oracle SQL Developer 中的脚本(为 table testData 创建 table 结构。0 行数据开头。)

DROP TABLE testData;
CREATE TABLE testData
  (
    NODENAME          VARCHAR2(64) NOT NULL,
    STORAGE_NAME      VARCHAR2(100) NOT NULL,
    TS                VARCHAR2(10) NOT NULL,
    STORAGE_TYPE      VARCHAR2(12) NOT NULL,
    CAPACITY_MB       VARCHAR2(11) NOT NULL,
    MAX_UTIL_PCT      VARCHAR2(12) NOT NULL,
    AVG_UTIL_PCT      VARCHAR2(12) NOT NULL,
    JOBRUN_START_TIME VARCHAR2(19) NOT NULL
  )
;
COMMIT;

正在进行的重复过程:

第 2、3 和 4 步:运行 SAS 中的此 SAS 代码

******************************************************;
******* On-going repeatable process starts here ******;
******************************************************;

*** Step 2: Trancate the temporary Oracle transaction dataset;
proc sql;
  connect to oracle (user=XXX password=YYY path=ZZZ);
  execute (
    truncate table testData
  ) by oracle;
  execute (
    commit
  ) by oracle;
  disconnect from oracle;
quit;

*** Step 3: Assign Oracle DB as a libname;
LIBNAME ora Oracle user=XXX password=YYY path=ZZZ dbcommit=100000;

*** Step 4: Insert data from SAS to Oracle;
PROC SQL; 
  insert into ora.testData
  select NODENAME length=64,
         STORAGE_NAME length=100,
         TS length=10,
         STORAGE_TYPE length=12,
         CAPACITY_MB length=11,
         MAX_UTIL_PCT length=12,
         AVG_UTIL_PCT length=12,
         JOBRUN_START_TIME length=19
  from work.testData; 
QUIT;

******************************************************;
**** On-going repeatable process ends here       *****;
******************************************************;

我的方法的局限性/问题:

Proc SQL 步骤(将 100 MB 数据从 SAS 传输到 Oracle)大约需要 5 个小时才能执行 - 该作业耗时太长 运行!

问题:

有没有更明智的方法来执行从 SAS 到 Oracle 的数据传输? (即从 SAS 更新 Oracle table)。

首先,如果有必要,您可以从 SAS 执行 drop/recreate。我不会每次都放弃并重新创建——截断似乎更容易获得相同的结果——但如果你有其他原因,那也没关系;但无论哪种方式,您都可以使用 execute (truncate table xyz) from oracle 或类似于 drop 的方式,使用直通连接。

其次,假设 table 上没有约束或索引 - 鉴于您正在删除并重新创建它,这似乎很可能 - 您可能无法改进这一点,因为它可能基于网络延迟.但是,您应该在连接设置(您未提供)中查看一个区域:SAS 提交数据的频率。

有两种控制方法,DBCOMMMIT setting and the BULKLOAD 设置。前者控制提交的执行频率(因此如果 DBCOMMIT=100 则每 100 行执行一次提交)。更频繁的提交 = 如果发生随机故障,则丢失的数据更少,但执行速度要慢得多。 PROC SQL INSERT 的 DBCOMMIT 默认为 0,这意味着只进行一次提交(假设没有错误的最快选项),因此除非您覆盖它,否则这不太可能有用。

Bulkload 可能是我的建议;它使用 SQLLDR 来加载您的数据,即,它将整个位分批传输到 Oracle,然后说 'Load this please, thanks.' 它只适用于某些设置和某些类型的查询,但它应该在这里工作(受其他条件限制 - 请阅读上面的文档页面)。

如果您使用的是 BULKLOAD,那么您可能会遇到网络延迟问题。 100 MB 5 小时似乎很慢,但我在(相对较短的)一天中看到了各种各样的事情。如果 BULKLOAD 不起作用,我可能会引入 Oracle DBA 并让他们解决这个问题,从一个 .csv 文件和一个 SQL*LDR 命令文件开始(这应该与 SAS 对 BULKLOAD 所做的基本相同);他们应该知道如何排除故障,并且至少能够监控数据库本身的性能。如果这里有问题的其他 tables 存在限制(即其他 tables 过于频繁地根据您的插入或其他内容重新计算自己),他们应该能够找出并推荐解决方案.

您可以查看 PROC DBLOAD,它有时比 SQL 中的插入速度更快(尽管总的来说不应该如此,而且 'older' 过程也未被使用很多了)。您还可以研究是否可以避免进行完全刷新和填充(即,如果有一种方法可以通过网络传输更少的数据),或者甚至可以简单地缩小列大小。