【问题标题】:multiples of 8 - optimal length for SAS character variables?8 的倍数 - SAS 字符变量的最佳长度?
【发布时间】:2015-10-21 04:52:21
【问题描述】:

我听说 SAS 以 8 个字节的块存储字符变量。

因此,我们应该始终将字符变量的长度分配为 8 的倍数。

我已经搜索并找不到任何对初始断言的支持。

这是真的吗?这在文档中的某处有介绍吗?

【问题讨论】:

  • @Joe,问题不在于变量名称,而是变量长度,由数据集上的长度语句设置。
  • 那你的问题就更没有意义了;但是您可以自己轻松地验证这一点,不是吗?
  • 没错,我可以凭经验验证。我希望知道的人能分享他们对 SAS 如何存储数据的见解。
  • 如果您想知道上述问题的答案,您应该... 测试一下。如果您想了解 SAS 如何存储数据,请提出那个问题。
  • 我做了自己的经验测试,并将其添加到下面作为答案。现在人们可以查一下这个问题了。

标签: sas


【解决方案1】:

这适用于不包含 8 字节数字变量的数据集。我将单独发布数据集。


不,8 字节字符可变长度没有什么特别之处。

见下文:

data length8;
  length char0001-char9999 $8;
  call missing(of _all_);
  do _i = 1 to 100; 
    output;
  end;
  drop _i;
run;
data length7;
  length char0001-char9999 $7;
  call missing(of _all_);
  do _i = 1 to 100; 
    output;
  end;
  drop _i;
run;

data length4;
  length char0001-char9999 $4;
  call missing(of _all_);
  do _i = 1 to 100; 
    output;
  end;
  drop _i;
run;

data length12;
  length char0001-char9999 $12;
  call missing(of _all_);
  do _i = 1 to 100; 
    output;
  end;
  drop _i;
run;

data length16;
  length char0001-char9999 $16;
  call missing(of _all_);
  do _i = 1 to 100; 
    output;
  end;
  drop _i;
run;

data length17;
  length char0001-char9999 $17;
  call missing(of _all_);
  do _i = 1 to 100; 
    output;
  end;
  drop _i;
run;

每个数据集的大小都不同,大致与字符变量的长度成正比。请注意,4 的大小按比例要大一些(无论如何,在我的机器上):实际上,4、5、6 的大小都相同。这是因为页面大小:我安装的最小页面大小为 64kb(65535 字节),而 4、5、6 都只能容纳其中的一行数据(大约 40、50 和 60kb 行)。这不是因为为字符变量保存了任何特定的大小,而是因为数据记录的总长度。

这就是您可以通过少量更改来节省成本的地方:如果您的数据恰好排列成页面大小刚好是行大小的两倍,那么将行稍微小一点可以节省一半的空间。除非在极少数情况下,否则这不太可能发生 - 它需要非常宽的行(许多变量或非常长的字符变量)。不过,您也可以使用选项更改页面大小,这可能是处理此类边缘情况的更好方法。

【讨论】:

    【解决方案2】:

    对于包含数字变量的数据集,正如@jaamor 的示例所包括的那样,存在对与 8 字节大小相关的存储产生一些影响的差异。它通常不会对数据集大小产生显着影响,除了非常高和窄的数据集,但对于 非常非常高和窄的数据集,可能是一个考虑因素。

    当数字变量的长度为 8 字节(默认值)时,SAS 将这些数字变量放在数据向量的末尾,并以 8 字节的倍数开始,大概是为了提高访问那些可预测变量的效率数值变量。除 8 字节数字之外的任何其他变量都将放置在数据向量的开头,然后添加使其达到 8 字节倍数所需的任何填充,然后将数字 8 字节变量放置在其后。

    这可以通过查看一些示例数据集的 proc contents 输出来看到。

    data fourteen_eight;
      length x y $7;  *14 total;
      length i 8;
    run;
    
    data twelve_eight;
      length x y $6;  *12 total;
      length i 8;
    run;
    
    data twelve_six;
      length x y $6;  *12 total;
      length i 6;
    run;
    
    data twelve_six_eight;
      length x y $6;
      length z 6;
      length i 8;
    run;
    

    fourteen_eight 的概念观察长度为 22,但物理观察长度为 24(查看PROC CONTENTS)。 twelve_eight 的概念长度为 20,但物理观察长度也为 24。 twelve_six 的概念长度为 18,物理观察长度为 18 - 如果数字变量不是 8 长,则表示没有缓冲区。 twelve_six_eight 的概念长度为 26,物理大小为 32:18 向上舍入为 24,最后是 8。 (您可以通过简单地添加几个 6 字节的数字来验证它没有为每个数字变量分配 8;它们不会增加总填充,并且整齐地适合更小的空间。)

    这是它最终的样子:

    • x $6
    • 6 美元
    • z 6
    • i 8

    应该是这样的:

    [00000000011111111112222222222333333333344444444445]
    [12345678901234567890123456789012345678901234567890]
    [xxxxxxyyyyyyzzzzzz      iiiiiiii]
    

    附注:我不能 100% 确定它不是 [iiiiiiiiixxxxxxyyyyyyzzzz ]。只要能够预测数字变量的位置,这将同样有效。但是,它并没有真正影响这一点:无论哪种方式,是的,如果您的总非 8 字节数字存储不是 8 字节的倍数(如果您确实有一个或多个 8 字节数字变量),则会有一个小缓冲区.

    【讨论】:

      【解决方案3】:

      正如乔所说,我确实使用以下脚本进行了经验性测试:

      libname testlen "<directory>";
      
      %macro create_ds(length=, dsName=);
          data &dsName;
              length x $&length.;
              do i=1 to 1000000;
                  x="";
                  output;
              end;
          run;
      %mend;
      
      %macro create_all_ds;
          %do i=1 %to 20;
              %create_ds(length=&i, dsName=testlen.len&i)
          %end;
      %mend;
      
      %create_all_ds
      

      所有数据集都有一个变量。变量的长度因数据集而异,从 1 到 20。

      数据集 1-8 占用 ~15.8 MB

      数据集 9-16 占用 ~23.7 MB

      数据集 16-20 占用 ~31.5 MB

      这可能意味着为 1 个变量数据集声明不是 8 的倍数的 SAS 变量长度是不节省空间的。

      我对 2 个变量数据集进行了类似的测试:

       %macro create_ds(length=, dsName=);
          data &dsName;
              length x y $&length.;
              do i=1 to 1000000;
                  x="";
                  y="";
                  output;
              end;
          run;
      %mend;
      
      %macro create_all_ds;
          %do i=1 %to 20;
              %create_ds(length=&i, dsName=testlen.len&i)
          %end;
      %mend;
      
      %create_all_ds
      

      结果如下:

      数据集 1-4 占用 ~15.8 MB

      数据集 5-8 占用 ~23.7 MB

      这可能意味着对于有效的长度声明,字符变量长度的总和应该是八的倍数。

      【讨论】:

      • 不幸的是(或幸运的是?),您犯了一个错误:您忘记删除i。放下它,看看情况如何变化。
      • 很棒的收获。删除 i 后,每个数据集都有不同的大小。
      猜你喜欢
      • 2017-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-05
      • 1970-01-01
      • 2015-09-02
      • 1970-01-01
      相关资源
      最近更新 更多