【问题标题】:ERROR: Out of memory错误:内存不足
【发布时间】:2014-01-05 11:28:34
【问题描述】:

运行输入为 ~5M obs 的程序时出现内存不足错误。和 153 个变量。

在 ~40,000 obs 上运行相同的程序时。 - 程序执行并完成得很好。 当我尝试增加输入 obs 的数量时。超过 100K - 我收到一个错误:内存不足。

我尝试遵循以下提示并取消选中几个框:

1.Tools ► Options ► Results General ► deselect all Result Formats.
2.Tools ► Options ► Results General ► deselect Open generated data/results automatically.
3.Tools ► Options ► Results General ► deselect Link handcoded ODS results.
4.Tools ► Options ► SAS Programs ► deselect Automatically direct results back to SAS Enterprise Guide.

仍然 - 不工作。

我使用的是企业指南 5.1 但最终会将工作代码插入到 Data Integration Studio 4.6 上的用户编写代码转换中。

有人知道如何让这个程序运行吗?

已编辑

这是导致错误消息的一段代码:

 data _null_;
        set all_include_Stornos ;
        IF TREATMENT_IND = 1 AND DDS_ROW_IND NE 1 THEN DO;
        CALL EXECUTE ('%STORNO_TKUFA ('||POLICY_RK||');');
        CALL EXECUTE ('%UPDATE (STORNO_TKUFA_CUMULATE);');
        END;
        IF TREATMENT_IND in (4) AND DDS_ROW_IND NE 1  THEN DO;

            CALL EXECUTE ('%HAKPAA ('||POLICY_RK||','||POLICY_VERSION||');');
            call execute ('%UPDATE(HAKPAA_CUMULATE);');


        END;

        IF TREATMENT_IND  = 5  AND DDS_ROW_IND NE 1  and count_bitul_no <2  or (count_bitul_no >1 and max_bitul_ver = policy_verSion ) THEN DO;
            CALL EXECUTE ('%BITUL ('||POLICY_RK||','||POLICY_VERSION||');');
            CALL EXECUTE ('%UPDATE(BITUL_CUMULATE);');

        END;

        IF TREATMENT_IND = 6 AND DDS_ROW_IND NE 1  THEN DO;
        CALL EXECUTE ('%LAST_STATE ('||POLICY_RK||','||POLICY_VERSION||');'); 
        CALL EXECUTE ('%UPDATE (LAST_STATE_calc);');
        END;

        IF DDS_ROW_IND NE 1 and ((PREV_TREATMENT_IND = 4 AND TREATMENT_IND NOT IN (1,2,5)) or treatment_ind = 3) THEN DO;
            CALL EXECUTE ('%HAFSHARA ('||POLICY_RK||','||POLICY_VERSION||');');
            CALL EXECUTE ('%UPDATE (HAFSHARA_CUMULATE);');
        END;

            IF TREATMENT_IND = 2 AND POLICY_VERSION - 1 = max_bitul_ver AND DDS_ROW_IND NE 1  THEN DO;
        CALL EXECUTE ('%STORNO_BITUL ('||POLICY_RK||','||POLICY_VERSION||');');
        CALL EXECUTE ('%UPDATE (STORNO_BITUL_CUMULATE);');
        END;
RUN; 

这些是在treatment_ind = 5时执行的2个宏(缩短):

%macro BITUL (pol_rk , pol_ver );


    proc sql;
    create table macro_BITUL
    as select * from all_include_Stornos
    where policy_rk = &pol_rk
    and treatment_ind_5 = &pol_ver 
    order by policy_rk, policy_version;
    quit;



    data BITUL_calc;
    set macro_BITUL;
    BY POLICY_RK;

    IF LAST.policy_rk THEN ACT_DAILY_AMT_END_DT = POLICY_VERSION_END_DT;
            ELSE ACT_DAILY_AMT_END_DT = NEXT_POLICY_VERSION_START_DT; 

    VERSION_EXPOSURE_DAYS_NO = ACT_DAILY_AMT_END_DT - ACT_DAILY_AMT_START_DT + 1;

    BITUL_DURATION =  (POLICY_EXPIRATION_DT_5 - POLICY_VERSION_START_DT + 1) / (POLICY_VERSION_END_DT_5 - POLICY_VERSION_START_DT + 1);

    GAINED_NET_PREMIUM_V_AMT  = NET_PREMIUM_V_AMT *BITUL_DURATION;
    .
    .
    .
    GAINED_NET_COMMISION_B_IB_V_AMT = PRODUCR_B_NET_COMM_IB_V_AMT * BITUL_DURATION; 
    run;

    /**/


    PROC SQL;
    CREATE TABLE TOTAL_GAINED AS 
    SELECT POLICY_RK,
    SUM(GAINED_NET_PREMIUM_V_AMT) AS TOT_GAINED_NET_PREMIUM_V_AMT,
    SUM(GAINED_NET_FEES_V_AMT) AS TOT_GAINED_NET_FEES_V_AMT,
    .
    .
    .
    SUM(GAINED_NET_COMMISION_B_IB_V_AMT) AS TOT_GAINED_NET_COMMN_B_IB_V_AMT 

    FROM BITUL_calc
    GROUP BY POLICY_RK;
    QUIT;

    PROC SQL;
    CREATE TABLE BITUL_calc_AND_TOTALS AS
    SELECT A.* , 
    TOT_GAINED_NET_PREMIUM_V_AMT,
    .
    .
    JOIN TOTAL_GAINED AS B
    ON
    (A.POLICY_rK = B.POLICY_RK
    )order  by policy_rk, policy_version;
    QUIT;




    DATA bitul_CALCULATED;
    SET BITUL_calc_AND_TOTALS;
    IF TOT_GAINED_NET_PREMIUM_V_AMT = 0 THEN CALCULATED_NET_PREMIUM_V_AMT = 0; 
        ELSE CALCULATED_NET_PREMIUM_V_AMT = NET_PREMIUM_AMT_5 * GAINED_NET_PREMIUM_V_AMT / TOT_GAINED_NET_PREMIUM_V_AMT;
    .
    .
        ELSE CALC_NET_COMMISION_B_IB_V_AMT = PRODUCR_B_NET_COMM_IB_AMT_5 * GAINED_NET_COMMISION_B_IB_V_AMT / TOT_GAINED_NET_COMMN_B_IB_V_AMT;


    .
    .
    .
    .
    .


    run;

    DATA BITUL_CUMULATE;
    SET bitul_CALCULATED;
.
.
.
.
.
.
run;    

%mend ;




%MACRO UPDATE (TABLE_NAME);
        PROC SQL;
            DELETE FROM all_include_Stornos
            WHERE CATS(POLICY_RK,POLICY_VERSION) IN ( SELECT CATS(POLICY_RK,POLICY_VERSION) FROM     &TABLE_NAME);
            INSERT INTO all_include_Stornos
select *    FROM &TABLE_NAME
            ;QUIT;

/*          PROC SORT DATA=all_include_Stornos OUT=all_include_Stornos; BY POLICY_RK     POLICY_VERSION;RUN;*/

%MEND;

【问题讨论】:

  • 我不是 EG 方面的专家,但是您是否尝试过这里的其他方法 support.sas.com/kb/40/480.html
  • 我确实做到了。收到错误消息... SAS 找不到路径或类似的东西
  • 好吧,如果它真的很长,你最好分小块运行它。这样,您就可以确定哪里出了问题。大多数内存问题都可以通过采用稍微不同的方法来解决,或者在某些情况下甚至可以通过添加单个关键字来解决。但是,当然,您需要查明失败的地方。
  • 根据我的经验,通常的嫌疑人往往是大型哈希合并,或者使用 proc 方法/摘要和跨越数百万级别的类语句,但这可能是完全不同的事情。你设置了哪些 memsize 和 sortsize 选项,你的机器有多少内存?
  • 我知道它在哪个数据步骤上让我失望。问题是,它是一个数据 null 根据 if 语句调用不同的宏。当我输入 80K 观察值运行代码时,我处理的表约为 50M。当我输入约 400K 观察值运行相同的过程时,我看到表权重约 500M。我没有得到任何效率低下的工作空间或其他任何错误。刚刚因内存不足错误而被抛出服务器。我编辑了我的帖子并插入了我正在谈论的数据 null。希望现在它会让你更有意义。无论如何,谢谢。

标签: sas enterprise-guide


【解决方案1】:

基于此:“我知道它在哪个数据步骤上将我抛出。问题是,它是一个数据 null 根据 if 语句调用不同的宏。”

看看Call Execute 是如何工作的。 (http://www2.sas.com/proceedings/sugi22/CODERS/PAPER70.PDF 会有所帮助)

基本上,Call Execute 将立即解析宏代码,但它会将生成的 SAS 步骤排入队列,直到当前数据步骤完成。换句话说,您可能会在内存中构建数百万行 SAS 代码,SAS 只是存储这些代码,以便在 data _null_; 步骤完成时执行。最终,它变得如此之大,以至于 SAS 只能崩溃。

如何处理?只需编写一个宏来将data _null_; 步骤分成块。您可以使用proc sql 将all_include_Stornos 中的记录数选择到宏变量中。然后使用宏循环多次运行数据步骤,使用firstobs 和obs 每次只命中一部分数据。这样,您可以将call execute 建立的缓冲区保持在合理的大小。这应该可以防止您内存不足。

【讨论】:

  • 我实际上正在考虑这样的解决方案,但我有一个问题我无法得到答案。我不能允许我的 RK 分布在 1 个以上的块中。不知道如何解决这个问题
  • 对其进行排序,为行块分配一个值,确保您不会在不同的块之间破坏 ID,然后一次处理 1 个块。
【解决方案2】:

根据编辑和您的评论,我怀疑“order by”和/或“proc sort”部分无法处理它正在运行的系统上的音量。

50M 是很多记录,但大多数人仍然可以管理。 但是,如果您的数据增长到 5 亿条记录,则可能太多了。

我记得我不久前有一个客户,其中数据集是 120M 行和 (iirc) +-300 个变量,我们确实遇到了类似的问题。
幸运的是,有一些方法可以处理大量数据。

1.使用标签排序选项
您可以将 tagsort 作为选项添加到 proc sort 语句。在这种情况下,SAS 仅使用 by 语句中的列进行排序,然后附加记录的剩余部分。它占用的资源较少,但当然速度较慢。

2.为 by 语句使用索引
如果您需要稍后在 proc/data 步骤中的 by 语句中将数据按特定顺序排列,您可以在这些变量上创建索引,而不是对数据进行排序。我的经验是,这将使 SAS 也能够处理更大的数据集。当然,它更慢,它消耗更多空间(用于索引)并且您需要考虑索引的存在(和破坏)。

3.拆分数据集,对部分进行排序,然后将所有内容拼接在一起
最后一种方法(在许多情况下可能比选项 2 更可取)是:

  1. 将数据集拆分为更小的数据集。
  2. 对每个较小的数据集进行排序。
  3. 使用简单的数据步骤将所有内容重新组合在一起。 (将所有较小的数据集放在 set 语句中,并使用您排序的 by 语句)

这个列表方法(和标签排序)在这里解释:http://www.nesug.org/Proceedings/nesug12/cc/cc36.pdf

请注意,所有这些方法都要求您摆脱任何 order by 并使用适当的排序过程跟进这些 proc sql 片段。

【讨论】:

  • PROC SORT 不会耗尽内存,只要OPTION SORTSIZE 没有设置在可用内存量之上;它只会使用磁盘。
  • 谢谢大家的回复。我试图将宏分解成碎片,逐行运行,直到它崩溃。我看到的是“内存不足”错误。这次没有断开连接,在简单的代码行上,没有任何可疑之处。当我将该行和所有行放在 cmets 之后 - 宏不会给我任何错误。所以我想这毕竟是一个内存问题。我使用了 proc 选项 group=memory;跑;按照建议,给出了 MEMSIZE=1073741824。奇怪的是,在服务器上,MEMSIZE 在配置文件中的值是 4GB ......所以现在我被卡住了,很困惑
  • 好的。所以内存问题得到了解决。 MEMSIZE 现在是 4GB,但程序仍然无法完成。我用完了选项
  • 未完成是什么意思?你得到同样的错误?一个不同的错误?还是它会永远运行? (或其他)
【解决方案3】:

首先,您需要检查为您的 sas 会话和排序分配了多少磁盘空间。这些选项称为 MEMSIZE 和 SORTSIZE

运行此代码,您将在日志中看到以字节为单位的值:

proc options group=memory option=(memsize sortsize) ; run;

我建议将此行添加为代码中的第一行,以分配 MAX 空间来排序大小:options sortsize=MAX; 并查看这是否解决了问题。

否则您可以将 MEMSIZE 更改为 MAX ,请按照此post 中的步骤操作。

【讨论】:

    【解决方案4】:

    在您的 CALL EXECUTE 语句中添加 %nrstr()。

    CALL EXECUTE ('%nrstr(%STORNO_TKUFA) ('||POLICY_RK||');');
    CALL EXECUTE ('%nrstr(%UPDATE) (STORNO_TKUFA_CUMULATE);');
    

    或者也许更好地更改您的数据_null_步骤以生成包含代码的文件并 %include 文件。

    filename code temp;
    data _null_;
      set all_include_Stornos ;
      IF TREATMENT_IND = 1 AND DDS_ROW_IND NE 1 THEN DO;
        put '%STORNO_TKUFA (' POLICY_RK ');';
        put '%UPDATE (STORNO_TKUFA_CUMULATE);';
    ...
    RUN;
    %include code ; 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-20
      • 2020-10-15
      • 2014-10-21
      • 2016-10-20
      • 2013-01-17
      • 2015-07-25
      相关资源
      最近更新 更多