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

Atl*_*as7 4 oracle sas

我试图解决的问题:

我有一个work.testData包含 8 列和大约 100 万行的 SAS 数据集(在工作库中)。所有列都是文本(即没有数字数据)。此 SAS 数据集的文件大小约为 100 MB。我的目标是将整个 SAS 数据集解析为 Oracle。即有点像从 SAS 平台到 Oracle 平台的 SAS 数据集的“复制和粘贴”。这背后的基本原理是,每天,Oracle 中的这个表都会被 SAS 中的表“替换”,这将启用下游 Oracle 流程。

我解决问题的方法:

Oracle 中的一次性初始设置:

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

不断重复的过程:

  1. 在 SAS 中,执行 SQL 传递以截断 ora.testData(即在保留表结构的同时删除所有行)。这确保 ora.testData 在从 SAS 插入之前为空。
  2. 在 SAS 中,用于将 Oracle 数据库指定为 SAS 库(称为 ora)的 LIBNAME 语句。因此,我可以“查看”Oracle 中的内容并从 SAS 执行读取/更新。
  3. 在 SAS 中,一个 PROC SQL 过程将 SAS 数据集 work.testData 中的数据“插入”到 Oracle 表 ora.testData 中。

示例代码

Oracle 中的一次性初始设置:

步骤 1:在 Oracle SQL Developer 中运行此 Oracle SQL 脚本(为表 testData 创建表结构。从 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;
Run Code Online (Sandbox Code Playgroud)

不断重复的过程:

步骤 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       *****;
******************************************************;
Run Code Online (Sandbox Code Playgroud)

我的方法的限制/问题:

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

问题:

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

Joe*_*Joe 6

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

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

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

批量加载可能是我的建议;使用 SQLLDR 加载您的数据,即,它将整个位分批处理到 Oracle,然后说“请加载这个,谢谢”。它只适用于某些设置和某些类型的查询,但它应该在这里工作(取决于其他条件 - 阅读上面的文档页面)。

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

您可以查看PROC DBLOAD,它有时比 SQL 中的插入更快(尽管总而言之不应该如此,并且是一个不再使用太多的“旧”过程)。您还可以考虑是否可以避免执行完全刷新和填充(即,是否有一种方法可以通过网络传输更少的数据),或者甚至只是缩小列大小。