【问题标题】:The fastest way to copy a huge dataset to server in SAS在 SAS 中将大型数据集复制到服务器的最快方法
【发布时间】:2014-12-12 01:14:51
【问题描述】:

10 月 21 日编辑

背景

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

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

  1. work.IMP 大约有 6M 条记录,每条记录大约 50 字节。
  2. 理想的方法应该是非常有效的,因为随着时间的推移,服务器上的原始数据集的大小会非常庞大​​。
  3. 一次性建立目标文件CANNOT,然后每天向其添加新数据。因为以前的数据可能(甚至非常不可能)发生变化。

根据@Joe,我应该允许更新目标文件,使用proc compare 或data step 中的update。这是我发布的一个相关问题How to use proc compare to update dataset

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

流程

  1. 首先我从excel文件中导入数据,然后subset&tranpose它是work.IMP。由于某些原因,此文件每天只能以这种方式创建。它CANNOT 存储在服务器中。
  2. 然后对work.IMP 和一个原始数据集Sourcelib.RAW1 执行外连接,得到work.HAVE1。请注意,work.IMP 已排序,但 Sourcelib.RAW1 未排序。外连接仅用于(根据某些条件)确定每条数据记录。

i.e. case when a.COL1 is '' then b.COL1 else a.COL1 end as COL1

你可以认为这个过程是通过使用work.IMP来调整Sourcelib.RAW1。

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

  1. 然后我将另一个原始数据集Sourcelib.RAW2 子集化为work.temp,然后将sort 子集化为work.HAVE2。 (Sourcelib.RAW2 中的数据大多是乱序的。)
  2. 我使用proc append(因为两个表都很大)将work.HAVE1、work.HAVE2连接成work.HAVE

PS2:step3中的排序是为了避免在step4的末尾排序。实际上数据Targerlib.WANT 不必按顺序排列。但最好是这样。

  1. 最后,我将work.HAVE 复制到服务器Targetlib.HAVE。

我在WORK 中完成了大部分工作,只花了我几分钟。但是step5 可能需要我半个小时才能完成副本。

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

问题

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

【问题讨论】:

  • A) 看起来您从 work.IMP 开始,然后将其拆分为两个数据集,然后将它们重新连接为一个。如果有某种方法可以避免这种情况,那就太好了 - 你能告诉我更多关于你在步骤 2 中所做的操作 B)你是在 Windows 还是 Linux 上运行?库的硬件情况如何(它们是否位于单独的磁盘上,这些磁盘是否属于某种 RAID,您的实用程序库 (UTILLOC) 的设置是什么等)?
  • 如果要跨服务器移动批量加载选项,您是否考虑过?
  • 这两个系统是同一个架构吗? IE两个Windows?
  • @sparc_spread 并没有真正将其一分为二。我已经用更多的操作细节编辑了我的问题。
  • @Reese 我使用了默认设置。我该如何优化呢?

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


【解决方案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 更快(如果本地写出可以忽略不计,因为它对我来说对于

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

【讨论】:

  • 第四点,我在工作中做到了这一切。所以它已经是本地的了?对于第5点,我应该将WORK中的@​​987654335@附加到网络中的HAVE,还是将网络中的HAVE2(我在上一步中将其放入网络)附加到网络中的HAVE?对于第三点,我已经用更多细节编辑了我的问题,你能看看这是否是你推荐的吗?对于compress 选项,我会尝试一下。谢谢。
  • proc compare 怎么能完成这项工作?不就是简单的返回不匹配的记录信息吗?
  • 没错。您使用它来识别不相同的记录,并且只加载那些记录。您可以指示它只返回来自 COMPARE 数据集的记录,并且只返回那些不同的记录,这将是您要加载的集合。
【解决方案2】:

您可以使用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;

这至少可以节省一些时间,但这仍然不能解决您的所有问题...我在 cmets 中提出了一些其他问题,并将根据这些问题尽可能多地更改此答案.


更新 1

这是一种一步完成左连接和连接并将结果立即写入targetlib 的方法。我不能保证这会更快,但值得一试。我使用key 和val 作为字段名称,替换为您认为合适的。

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。这可能会给你更多的洞察力。另外,我假设 IMP 已经从 Excel 导入,并且它在 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 link 和 this older but more comprehensive one。

可能更有效的一种方法是避免连接并改用散列对象:散列对象can be found here 和a good tip sheet is here 的良好文档。目前尚不清楚这是否会更快 - imp 有 6m 条记录,但每条记录 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,并找到将多个操作组合成一个来自 PROC 或 DATA 步骤的单个写入的方法。


【讨论】:

  • proc append 将避免读取来自data= 的记录。在上面的方法中,Targetlib.HAVE 首先设置为空,然后附加两个大型数据集HAVE1,HAVE2。那么我们还需要从那些大型数据集中读取所有记录吗?
  • 是的,这只是为了跳过您最初的步骤之一。但是我正在研究新的东西,应该很快就会发布......请参阅原始帖子中 cmets 中的问题。
  • WARNING 30-12: SAS option SGIO is valid only at startup of the SAS System. The SAS option is ignored.
  • 错误信息具有误导性。这意味着数据集太小而无法使用 SGIO。有关详细信息,请参阅 (support.sas.com/resources/papers/Flexibility_by_Design.pdf) 和 (support.sas.com/documentation/cdl/en/hostwin/67279/PDF/default/…)。
  • 服务器是基于 sql 的。我已经尝试了各种方法来优化代码,但是性能仍然很差。(但是 ms-sql 可以在不到 2 分钟的时间内完成)。我想这与mattets的服务器架构有关。
猜你喜欢
  • 2021-11-12
  • 2015-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多