我有一个非常大的数据集和一个中等大小的数据集。我想将较小的一个哈希合并到较大的一个上。我只需要在生成的合并中保留一小部分行/列,因此我使用的方法是使用SAS / CONNECT启动多个并行会话,并让每个会话处理一个单独的行范围。极大的数据集。当每个并行哈希合并完成后,我将各个部分附加在一起。
我遇到的问题是,每个并行会话都需要在内存中保留自己的中等大小数据集副本,因此当会话数量时,可用系统内存量很快成为性能瓶颈扩大规模。是否有一种方法可以让一个SAS会话访问另一个会话的哈希对象,或者某种其他方法可以提供相同的性能优势而不需要每个并行会话需要1个内存中的副本?
我唯一能想到的就是将中等大小的数据集复制到ramdisk,并将哈希合并更改为索引合并。还有其他值得考虑的选择吗?
我已经尝试过Reeza建议使用基于存储在所有并行会话使用的公共库中的格式定义的格式合并,但我发现每个会话最终都需要额外的内存与散列合并的方式完全相同。在使用该格式的单个过程或数据步骤的完整统计数据中没有报告这一点,但在注销会话或使用适当的OS工具时很明显。
答案 0 :(得分:0)
如果我正确理解这一点,问题是您无法在单个会话中执行此操作,因为您无法将极大的表加载到内存中。
我之前遇到过这个问题,并找出了一种解决方法(虽然有点复杂),它允许您有效地删除哈希对象的内存限制,同时最大限度地减少开销。
基本前提是通过键盘对您的超大桌子以及您的小桌子进行排序。首先(这是唯一的开销)。即使现在对它们进行了排序,使用索引仍然比在这些非常大的表上进行散列要慢得多(我的大表是大约1B行,而我的小表是数百万行,尽管它可以是任何大小)。
接下来,您要计算一大堆关于大型表的元数据。我们的想法是将其分成足够的桶,以便每个桶足够小以适应内存,每个桶包含顺序数据(由早期类型处理)。您还需要确保给定密钥仅存在于单个存储桶中。
例如,如果我有十亿行,并且我知道我一次可以将100万行放入内存中,我会计算出如下所示的元数据:
bucket first_obs last_obs key_min key_max
====== ========= =========== ========== ===========
1 1 10000000 a a23
2 10000001 20000000 a24 c19
...
...
100 999000001 1000000000 z394883 zzzzzzzz
最后一步类似于常规哈希表/ datastep进程。最初,您将第一个桶加载到哈希表中,并且每次迭代datastep都会检查您的键值是否意味着您需要加载下一个桶。如果是,请删除哈希表(使用ht.delete()
)并将下一个桶加载到其中。您可以使用以下代码中的代码执行此操作:
declare hash ht&cnt(dataset:"largeds(firstobs=&first_obs obs=&last_obs)");
因为在加载下一组数据之前删除哈希表,所以内存不会用完。您只需要将每个桶加载到内存中一次,并且您只需要遍历较小的数据集一次,因此该方法非常有效(特别是如果两组数据已经按键排序)。您可以在datastep中定义的哈希表的数量也没有限制,因此我的宏代码可能已经解析为声明100个哈希表(虽然一次只包含1个数据)。
您很可能希望在宏中构建此datastep以轻松使用元数据。
有点麻烦,但如果你需要非常有效的东西,那值得付出努力。如果SAS自己添加了这种功能,那就太好了......