在SAS中将大型数据集复制到服务器的最快方法

时间:2014-10-16 15:32:40

标签: sql-server sas processing-efficiency memory-efficient

于10月21日编辑

背景

存储在基于MS-SQL的服务器上的原始数据集(每天更改):Sourcelib.RAWLOCAL excel文件(保留unchanged)。

我需要刷新位于WANT的数据集Targerlib。目前我有SQL代码在2-3分钟内执行此类任务。但我想知道SAS是否可以做同样的事情,而处理时间不会增加太多。

  1. work.IMP约为6M记录,每条记录约50个字节。
  2. 理想的方法应该非常有效,因为随着时间的推移,服务器上原始数据集的大小将非常大。
  3. 目标文件CANNOT一次建立,然后每天向其添加新数据。因为以前的数据可能(甚至非常不可能)发生变化。
  4. 根据@Joe,我应该允许在proc compare中使用updatedata step更新目标文件。这是我发布的相关问题How to use proc compare to update dataset

    1. 服务器上的可用空间超过10GB,这已足够。我的电脑中的可用内存大约为3.5GB(不确定是否重要)
    2. 由于服务器的体系结构,在MS-SQL中执行它非常有效。但我真的想知道SAS是否可以处理这个问题(当服务器不是"compatible"时)
    3. 过程

      1. 首先我从excel文件导入数据,然后将subset&tranpose导入work.IMP。由于某些原因,此文件只能以这种方式创建。它CANNOT存储在服务器中。
      2. 然后为work.IMP和一个原始数据集Sourcelib.RAW1执行外部联接以获取work.HAVE1。请注意,work.IMP已排序,但Sourcelib.RAW1未排序。外连接仅用于(有一些标准)确定每个数据记录。
      3. i.e. case when a.COL1 is '' then b.COL1 else a.COL1 end as COL1

        您可以认为此过程是使用Sourcelib.RAW1调整work.IMP

        PS1:@sparc_spread建议直接向服务器执行导入过程。但它在LOCAL中没有任何好处。此处的hash object也无济于事。

        1. 然后我将另一个原始数据集Sourcelib.RAW2配置为work.temp,然后将sort配置为work.HAVE2。 (Sourcelib.RAW2中的数据大部分都没有按顺序排列。)
        2. 我使用work.HAVE1连接work.HAVE2proc append(因为两个表都很大)是work.HAVE
        3. PS2:step3中的排序是为了避免在step4结束时进行排序。实际上,数据Targerlib.WANT不一定是有序的。但最好这样做。

          1. 最后,我将work.HAVE复制到服务器Targetlib.HAVE
          2. 我在WORK做了大部分事情,这只花了我几分钟。但step5可能需要半个小时才能完成复制。

            根据@Joe,这可能主要是由于与网络传输有关的事情。 I.E最小化网络传输

            问题

            有什么方法可以改善step5?或者对整个过程进行任何修改都会改善性能?

2 个答案:

答案 0 :(得分:1)

一些想法。

首先,假设这是一个SAS数据集而不是SQL数据库或其他东西,options compress=binary;是一个好主意,假设这主要是数字(如果没有,则为options compress=character;)。在大多数情况下,要么会显着减小数据集的物理尺寸。

其次,300MB在事物计划中并不是很多。我的网络会在不到一分钟的时间内写出来。您的网络条件可能会推动您做出的其他一些选择;例如,如果单个慢点就是简单地在其上复制数据,那么你需要弄清楚如何以你做任何其他事情为代价来减少数据。

假设您没有更改任何其他内容,我建议您将have1直接写为网络have,然后将have2添加到网络中。 IE,无论创建have1的步骤,都可以直接写入网络。这包括sort步骤,请注意:因此,如果您创建它,则对其进行排序,在本地创建并使用out=网络库对其进行排序。这样可以减少写入的总量(因为您没有将have1的无用副本写入本地驱动器)。这有助于在本地写作是整个过程的相关成本,但如果它几乎完全是网络拥塞则无济于事。

使用操作系统副本复制文件几乎总是优于任何其他复制方法,因此如果网络拥塞是您唯一关心的因素,您可能希望在本地创建(在WORK或本地但常量目录中,比如C:\temp\或类似的),然后让您的流程的最后一步执行copy c:\temp\have.sas7bdat \\networklocation\whereitgoes\。这通常会优于SAS方法,因为它可以利用有效的技术。

PROC COPY是解决网络拥塞的另一种选择;它可能比PROC APPEND快(如果本地写出可以忽略不计,就像我对<1 GB数据那样),并且具有在运输过程中发生某些事情时更安全的优点。 (附加也应该没问题,但是你知道COPY肯定没有改变昨天的文件。)

最后,您可能想要找出一些方法来允许更新目标文件。在大多数情况下,这并不是那么难。一个例子是保留昨天文件的副本,对今天的文件执行PROC COMPARE,然后在更新文件中包含每个更改的记录(无论更改是什么)。然后从目标文件中删除任何匹配的旧记录并附加新记录。相对于通过网络发送的总记录而言,这是非常快的,因此如果网络拥塞是主要问题,则可以节省大量时间(但需要更多的CPU时间来进行PROC COMPARE)。

答案 1 :(得分:0)

您可以使用PROC APPEND有效地创建新数据集,而不仅仅是附加到现有数据集 - 因此您可以使用它基本上将步骤3和4合并到此中:

/* To fulfill requirement 4, delete existing Targetlib.HAVE */
PROC DELETE LIBRARY="Targetlib" DATA="HAVE"; 
RUN;

/* Targetlib.HAVE does not yet exist, the first APPEND will create it */
PROC APPEND BASE="Targetlib.HAVE" DATA="work.HAVE1";
RUN;

PROC APPEND BASE="Targetlib.HAVE" DATA="work.HAVE2";
RUN;

这应该至少节省一些时间,但这仍然无法解决你所有的问题......我在问题的评论中还有一些额外的问题,并且会尽可能地根据它们改变这个答案


更新1

以下是一种在一步中执行左连接和连接的方法,并立即将结果写入targetlib。我无法保证这会更快,但值得一试。我使用keyval作为字段名称,根据您的需要进行替换。

PROC SQL _METHOD;
    CREATE TABLE targetlib.HAVE
    AS
    SELECT
        a.key ,
        CASE WHEN MISSING (a.val) THEN b.val ELSE a.val END AS val  
    FROM
        Sourcelib.RAW1 AS a
    LEFT JOIN
        IMP AS b
        ON
            a.key = b.key
    UNION
    SELECT
        c.*
    FROM
        Sourcelib.RAW2 AS c
    ORDER BY
        key
;
QUIT;
RUN;

_METHOD是一个记录稀疏的SAS功能,将打印查询计划,请参阅this link。这可能会给你更多的见解。另外,我假设已经从Excel导入了IMP,并且它位于WORK中。尝试查看是否将其导入targetlib并将IMP as b替换为targetlib.IMP as b更快。

由于您使用的是Windows,请在数据集名称后尝试数据选项SGIO=YES:例如: Sourcelib.RAW1 AS a变为Sourcelib.RAW1 (SGIO=YES) AS a。有关Windows SGIO和SAS的详细信息,请参阅this linkthis older but more comprehensive one

可能更高效的方法是避免连接并改为使用哈希对象:哈希对象can be found herea good tip sheet is here的良好文档。目前尚不清楚这是否会更快 - imp有6米的记录,但每个记录50个字节,大约300 MB,这适合你的RAM。具有那么多条目的哈希表的性能很大程度上取决于SAS的哈希算法。无论如何,这是使用哈希对象的代码。在其中,我们假设在IMP数据集中,val字段已重命名为val2

DATA targetlib.HAVE (DROP = rc val2);
    LENGTH val2 8. ;

    IF (_N_ = 1) THEN DO;
        DECLARE HASH h (DATASET: "IMP") ;
        h.DEFINEKEY ('key');
        h.DEFINEDATA ('val2');
        h.DEFINEDONE ();
    END;

    SET 
        sourcelib.RAW1
        sourcelib.RAW2
    ;

    IF MISSING (val) THEN DO;
        rc = h.find();
        IF (rc = 0) THEN DO;
            val = val2;
        END;
    END;
RUN;
PROC SORT DATA = targetlib.HAVE ; BY KEY ; RUN ;

尝试一下,看看它是否更快。再一次,使用IMP等来试验SGIO的位置。最后PROC SORT可能很贵;如果您之前排序的唯一原因是因为加入,那么跳过它。

通常,您使用SAS的方法应该是尽可能少的I / O,并找到将多个操作组合到PROCDATA步骤的单个写入中的方法。