Proc SQL:SAS如何/何时移动数据

Cho*_*ens 2 sas

我是DBA/R用户.我刚刚在一个充满SAS用户的办公室找到了一份工作,我正在努力更好地理解SAS的proc sql是如何工作的.我知道SAS包含一个关系数据库,它包括对Oracle等外部服务器运行proc sql的能力.我试图更好地了解它何时/如何决定使用数据库服务器而不是其内部数据库系统.

我见过一些非常慢的SLOW SAS代码,我的同事运行一系列proc sql命令.这些程序通常包括3-5个proc sql步骤.每个proc sql命令都会创建一个本地SAS表.他们没有使用passthrough sql.数据集很大(100万行+),这些proc sql步骤运行缓慢.大多数数据都存在于服务器上.通常有一个小表来定义我们想要查看的填充,它位于SAS数据文件中,但其他所有内容都存在于服务器上.

通过直接在服务器上运行所有查询,我已经证明了速度的显着提高.(在这种情况下是Oracle,但我认为这不重要.)通常,我必须首先将一个表上传到我的个人模式,该模式定义了我们想要检查的客户群.其他一切都在服务器上.有时我会将他们的查询合并在一起,因为它们可以在一个步骤中完成,但我不相信这就是为什么我的程序版本更快.

我认为proc sql上传了初始数据集,然后在服务器上运行第一个查询.然后,它将输出下载到本地计算机,创建本地SAS数据集.对于第二个proc sql步骤,它将在步骤1中创建的表上载回服务器,然后在服务器上运行查询.更糟糕的是,"本地"SAS数据集实际上存储在远程服务器上,而不是实际的本地机器上.这对SAS来说是不可见的,但它确实意味着我们再次在网络上复制数据.我认为SAS由于大量不必要的网络流量而运行缓慢.

问题#1 - 我对proc sql的正确理解是什么?我们是否真的在浪费尽可能多的时间,因为我认为我们正在通过网络上传和下载大型表格/数据集?

Qeustion#2 - 是否有某种方法可以控制proc sql针对服务器运行的时间与针对本地数据库运行的时间?在某些情况下,如果我们可以阻止上传/下载步骤,查询将更有效地运行.

Joe*_*Joe 8

简短的回答

你的理解并不完全正确,但它是在正确的球场.SQL可能没有将SAS数据集发送到服务器,更有可能将服务器数据下载到SAS - 但它可能正在下载整个表,而不受连接标准的限制.您的解决方案正是我建议您做的 - 希望您的同事能够加入.


答案很长

就处理的工作方式而言,这取决于您的代码. PROC SQL将在本地执行代码(如在SAS服务器/桌面上),除非它决定将查询传递给服务器并且没有被告知它不被允许.这就是所谓的implicit passthrough.你不能真正控制它,除非完全关闭它(noipassthruPROC SQL声明中).您可以使用options msglevel=i;(系统选项)查看它,_METHOD或者_TREE查看SQL决定做什么(类似于解释计划).

我遇到过它造成伤害的情况:SQL Server运行字符比较不区分大小写,而SAS则没有,我有一个特定的查询,有时发送到服务器,有时不依赖于数据的细节.我对检查案例不够谨慎,所以当它真的不正确时它似乎工作(比较Propcase和UPCASE).

一般规则是,如果出现以下情况,SAS将尝试将查询发送到服务器:

  • 查询中的数据完全已驻留在服务器上
  • 查询非常简单,SAS可以用其母语轻松地弄清楚如何告诉服务器执行此操作

如果您正在使用本地SAS数据集运行查询(例如,在本地将服务器表连接到SAS数据集),则不会(至少据我所知)去服务器.它应该始终在本地运行,这意味着从服务器下载贡献表中的所有数据(如果查询中有逻辑过滤器,可能会过滤).IE(这些示例不一定是好的SQL代码,只是概念的例子):

libname oralib oracle [connection info];
proc sql;
*Will pass through likely;
select tableA.*, tableB.cost 
  from oralib.tableA inner join oralib.tableB 
  on tableA.id=tableB.id;
*Will probably not pass through;
select tableA.*, tableB.cost 
  from oralib.tableA inner join work.tableB
  on tableA.id=tableB.id;
*Might pass through, might not;
select tableA.*, tableB.cost, tableC.productID
  from oralib.tableA inner join oralib.tableB 
  on tableA.id=tableB.id
  left join oralib.tableC
  on tableA.id=tableC.id;
*This downloads the data but probably applies the where statement server side;
select tableA.*, tableB.cost 
  from oralib.tableA inner join work.tableB
  on tableA.id=tableB.id
  where tableA.date < '01JAN2010'd;
quit;
Run Code Online (Sandbox Code Playgroud)

在第二个查询的情况下,它可能会将所有tableA拉下来.在第四个查询中,它可能会将where子句传递给服务器(假设日期不会导致问题,但它不应该,SAS知道如何将日期转换为oracle类型日期).

请注意,SAS触发器也可以生成passthrough.PROC MEANS等会将指令发送给Oracle以执行手段/总和/等.如果它可以很容易地这样做.

你最好的选择是:

  1. 尝试尽可能地完成所有事情(这是有道理的).确保它进入服务器的唯一方法是使用passthrough.
  2. 如果服务器上有一个大表,SAS中有一个小表,请将SAS中的表上传到服务器.直通会话和libname会话无法看到每个其他会话特定的临时表,因此您必须使用GTT或类似(所有用户都可以看到的内容).同样,如果在SAS中有一个大表,在SQL中有一个小表(或小查询结果),请在本地将其关闭(必要时通过passthrough).
  3. 当你不得不把事情搞砸时,尽可能地限制.当我在这种环境中工作时,我只需加入服务器上的表来限制我的结果集,然后降低它们,从而节省了大量时间.

在一天结束时,无论你做什么,你都会受到网络流量的限制; 尽量优化它.听起来你已经明白了如何做到这一点,所以只要做你在非SAS环境中通常会做的事情.