大型数据集的PROC SQL更新效率

大型数据集的PROC SQL更新效率,sql,performance,sas,large-data,Sql,Performance,Sas,Large Data,我有一个SAS主数据集,有1000万行和1800列。我需要使用具有1500万条记录的事务数据集更新10列,仅针对具有匹配键的记录。 我尝试使用以下代码运行proc sql update语句 proc sql; UPDATE lib1.master1 a SET col1 = (SELECT col1 FROM lib1.changes_1 b WHERE a.key=b.key), col2 = (SELECT col2 FROM lib1.changes_1 b WHERE a.ke

我有一个SAS主数据集,有1000万行和1800列。我需要使用具有1500万条记录的事务数据集更新10列,仅针对具有匹配键的记录。 我尝试使用以下代码运行proc sql update语句

proc sql;
UPDATE lib1.master1 a

SET col1 = (SELECT col1 FROM lib1.changes_1 b WHERE a.key=b.key),
    col2 = (SELECT col2 FROM lib1.changes_1 b WHERE a.key=b.key),
    col3 = (SELECT col3 FROM lib1.changes_1 b WHERE a.key=b.key),
    col4 = (SELECT col4 FROM lib1.changes_1 b WHERE a.key=b.key),
    col5 = (SELECT col5 FROM lib1.changes_1 b WHERE a.key=b.key),
    col6 = (SELECT col6 FROM lib1.changes_1 b WHERE a.key=b.key),
    col7 = (SELECT col7 FROM lib1.changes_1 b WHERE a.key=b.key),
    col8 = (SELECT col8 FROM lib1.changes_1 b WHERE a.key=b.key),
    col9 = (SELECT col9 FROM lib1.changes_1 b WHERE a.key=b.key)

WHERE EXISTS ( SELECT 1 FROM lib1.changes_1 b WHERE A.key = B.key);
quit;
为了测试,我尝试了col1,它已经运行了4个多小时

我可以考虑数据合并,方法是删除10列,然后左连接,但这会改变列的顺序。重新排列1800列将再次成为一项乏味的任务


有没有更快/更有效的技术?

您面临一个挑战。首先,我建议在
lib1.changes\u 1(key)
上创建一个索引,如果您没有索引的话。这可能会大大提高性能

proc-sql
不支持更新中的
join
——这正是您真正需要的。然而,许多底层数据引擎确实如此。因此,如果您正在与数据库中的数据(如MySQL、Postgres或SQL Server)通信,那么您可以编写一个本机模式查询,使用
join
进行更新


全SAS解决方案是使用数据步骤。

您面临一个挑战。首先,我建议在
lib1.changes\u 1(key)
上创建一个索引,如果您没有索引的话。这可能会大大提高性能

proc-sql
不支持更新中的
join
——这正是您真正需要的。然而,许多底层数据引擎确实如此。因此,如果您正在与数据库中的数据(如MySQL、Postgres或SQL Server)通信,那么您可以编写一个本机模式查询,使用
join
进行更新


全SAS解决方案是使用数据步骤。

如何为事务数据集中的10列中的每列生成格式

生成虚拟数据集:
主数据集(10M记录)和
事务数据集(15M记录):
(原始的
事务
数据集在下面标准化,以准备创建每个事务变量的格式)

以格式读入:

proc format cntlin=transaction ;
run ;
data want ;
  set master ;
    col1=put(key,COL1F.) ;
    col2=put(key,COL2F.) ;
    col3=put(key,COL3F.) ;
    col4=put(key,COL4F.) ;
    col5=put(key,COL5F.) ;
    col6=put(key,COL6F.) ;
    col7=put(key,COL7F.) ;
    col8=put(key,COL8F.) ;
    col9=put(key,COL9F.) ;
    col10=put(key,COL10F.) ;
    output ;
run ;
然后将格式应用于
主数据集:

proc format cntlin=transaction ;
run ;
data want ;
  set master ;
    col1=put(key,COL1F.) ;
    col2=put(key,COL2F.) ;
    col3=put(key,COL3F.) ;
    col4=put(key,COL4F.) ;
    col5=put(key,COL5F.) ;
    col6=put(key,COL6F.) ;
    col7=put(key,COL7F.) ;
    col8=put(key,COL8F.) ;
    col9=put(key,COL9F.) ;
    col10=put(key,COL10F.) ;
    output ;
run ;

如何为事务数据集中的10列中的每一列生成格式

生成虚拟数据集:
主数据集(10M记录)和
事务数据集(15M记录):
(原始的
事务
数据集在下面标准化,以准备创建每个事务变量的格式)

以格式读入:

proc format cntlin=transaction ;
run ;
data want ;
  set master ;
    col1=put(key,COL1F.) ;
    col2=put(key,COL2F.) ;
    col3=put(key,COL3F.) ;
    col4=put(key,COL4F.) ;
    col5=put(key,COL5F.) ;
    col6=put(key,COL6F.) ;
    col7=put(key,COL7F.) ;
    col8=put(key,COL8F.) ;
    col9=put(key,COL9F.) ;
    col10=put(key,COL10F.) ;
    output ;
run ;
然后将格式应用于
主数据集:

proc format cntlin=transaction ;
run ;
data want ;
  set master ;
    col1=put(key,COL1F.) ;
    col2=put(key,COL2F.) ;
    col3=put(key,COL3F.) ;
    col4=put(key,COL4F.) ;
    col5=put(key,COL5F.) ;
    col6=put(key,COL6F.) ;
    col7=put(key,COL7F.) ;
    col8=put(key,COL8F.) ;
    col9=put(key,COL9F.) ;
    col10=put(key,COL10F.) ;
    output ;
run ;
总结
  • Rollup
    lib1。将\u 1
    更改为临时表(例如,
    lib1。更改\u 1\u rolledup
    ),执行完全扫描。(
    lib1.changes\u rolledup
    的物理属性应该仔细设置。)
  • 使用
    lib1更新
    lib1.master1
    。更改rolledup
    的数据,执行其中一个的完全扫描和另一个的索引扫描。(哪一个要完全扫描取决于实际数据。)
  • 解释 首先,为了获得更好的性能,您很可能需要深入底层DBMS级别并利用其功能

    然后,优化技术实际上取决于数据的性质

    我假设[几乎]所有的
    lib1.changes\u 1(key)
    值都与
    lib1.master1(key)
    值中的一个匹配(
    lib1.changes\u 1
    甚至可能是
    lib1.master1
    的详细表)。此外,我们还需要应用
    lib1.changes\u 1
    中的所有更改。这意味着我们必须从
    lib1.changes\u 1
    读取所有记录。如果是这样,最有效的方法是执行
    lib1.changes\u 1
    表完整扫描,但只执行一次。此完整扫描将汇总来自
    lib1的所有更改。更改\u 1
    为此类定义的(可能的临时)表:

    -- pseudo code:
    create [temporary] table lib1.changes_1_rolledup 
      <set physical attributes depending on your data nature - see below>
      as select key, col1, col2, col3, col4, col5, col6, col7, col8, col9
      from lib1.changes_1
      where 1 = 2
    
    总结
  • Rollup
    lib1。将\u 1
    更改为临时表(例如,
    lib1。更改\u 1\u rolledup
    ),执行完全扫描。(
    lib1.changes\u rolledup
    的物理属性应该仔细设置。)
  • 使用
    lib1更新
    lib1.master1
    。更改rolledup
    的数据,执行其中一个的完全扫描和另一个的索引扫描。(哪一个要完全扫描取决于实际数据。)
  • 解释 首先,为了获得更好的性能,您很可能需要深入底层DBMS级别并利用其功能

    然后,优化技术实际上取决于数据的性质

    我假设[几乎]所有的
    lib1.changes\u 1(key)
    值都与
    lib1.master1(key)
    值中的一个匹配(
    lib1.changes\u 1
    甚至可能是
    lib1.master1
    的详细表)。此外,我们还需要应用
    lib1.changes\u 1
    中的所有更改。这意味着我们必须从
    lib1.changes\u 1
    读取所有记录。如果是这样,最有效的方法是执行
    lib1.changes\u 1
    表完整扫描,但只执行一次。此完整扫描将汇总来自
    lib1的所有更改。更改\u 1
    为此类定义的(可能的临时)表:

    -- pseudo code:
    create [temporary] table lib1.changes_1_rolledup 
      <set physical attributes depending on your data nature - see below>
      as select key, col1, col2, col3, col4, col5, col6, col7, col8, col9
      from lib1.changes_1
      where 1 = 2
    

    要替换一列,格式(大致类似于Bendy的方法)是最简单的

    要替换始终来自同一行的十列,我建议使用哈希表。通常与单一格式的速度相同。(在10MM行标记处,格式实际上可能有点慢,因此这可能比一行更快。)

    这在我的笔记本电脑上花费了约30秒的时间(CPU时间和实时;我有一个SSD,所以它们类似。在HDD上,这可能是30秒的CPU时间和几分钟的实时时间。)


    要替换一列,格式(大致类似于Bendy的方法)是最简单的。