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

时间:2015-02-02 12:59:24

标签: oracle sas

我想解决的问题:

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

我解决问题的方法:

Oracle中的一次性初始设置:

  1. 在Oracle中,我创建了一个名为testData的表,其表结构与SAS数据集testData几乎完全相同。 (即相同的表名,相同的列数,相同的列名等)。
  2. 正在进行的重复过程:

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

      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;
      

      正在进行的重复过程:

      步骤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表)。

1 个答案:

答案 0 :(得分:4)

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

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

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

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

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

您可以查看PROC DBLOAD,它有时比SQL中的插入更快(尽管总的来说不应该是,并且是'旧的'过程不再使用太多)。您还可以查看是否可以避免执行完全刷新和填充(即,是否有通过网络传输较少数据的方法),甚至只是缩小列大小。