【问题标题】:SQL - not exists query with millions of recordsSQL - 不存在具有数百万条记录的查询
【发布时间】:2015-10-04 11:30:09
【问题描述】:

我正在尝试使用以下 SQL 查询(在 SAS 中)从 pool1 中查找 pool2 中不存在的任何记录。 Pool1 有 11,000,000 条记录,pool2 有 700,000 条记录。这是我遇到问题的地方。我让查询运行了 16 个小时,但离完成还差得很远。有没有更有效的方法(在 SQL 或 SAS 中)来实现我需要做的事情?

PROC SQL;
CREATE TABLE ALL AS
SELECT A.ID
FROM POOL1 A
WHERE NOT EXISTS (SELECT B.ID
                  FROM POOL2 B
                  WHERE B.ID = A.ID);
QUIT;

【问题讨论】:

  • 所以查询应该返回 10,300,000 条记录?
  • @Matt 。 . .不,这些将进入表格all
  • 重复表A怎么样,然后从表A中删除表B中存在的记录。
  • 在完美的 (SQL) 世界中,a.id 和 b.id 将是(主)键。 SAS 没有键,因此您必须通过在 a.id 和 b.id 上添加(唯一?)索引来模拟它们。
  • 不需要索引。请参阅下面的@Steve Matthews 答案。

标签: sql sas not-exists


【解决方案1】:

您的查询很好。在大多数数据库中,not exists 是表达这种逻辑的最佳方式(或最佳方式之一)。

但是,您需要一个性能索引:

create index idx_pool2_id on pool2(id);

【讨论】:

    【解决方案2】:
    PROC SQL;
    CREATE TABLE ALL AS
    SELECT A.ID
      FROM POOL1 A
           LEFT JOIN POOL2 B ON B.ID = A.ID
     WHERE B.ID IS NULL
    

    【讨论】:

      【解决方案3】:
      PROC SQL;
      CREATE TABLE ALL AS
      SELECT A.ID
          FROM
              POOL1 A
          WHERE A.ID NOT IN (SELECT B.ID
                              FROM
                                  POOL2 B)
                              ;
      

      上述更改应该返回相同的结果集,但运行时间要少得多,因为您不是试图将 POOL2 加入回 POOL1,而是简单地排除 POOL2 中存在的结果。

      正如另一个答案中所述,INDEX 可能会有所帮助,但如果 ID 字段是主键,则它们很可能已经在 INDEX 中受到影响。

      【讨论】:

      • 这是我发现在 SAS 中解决此问题的最佳方法。通过带有子查询连接的NOT EXISTS 语句运行一个记录数减少 100 倍的玩具问题需要 14 秒。此方法耗时 0.03 秒!玩具中没有创建任何索引。
      • 另外值得注意的是,通过这种没有索引的方法,11,000,000 和 700,000 条记录的完整玩具问题需要 5 秒。
      • 哇,这有点违反直觉。我想知道它是否在内部使用哈希查找来实现这种速度......
      • @RobertPenr​​idge,我猜是这样。大多数时候可能是对较小的表进行排序/索引/散列(无论如何)内部查询的结果。如果您颠倒表格,这将花费更长的时间。
      • 在 ID 字段上没有任何索引,您可以看到它实际在做什么的详细信息;它将执行表扫描以提取 ID,然后对提取的字段进行升序排序,然后执行反半联接以清除要排除的结果,利用它已经对它们进行排序的事实。添加索引,您看到的只是聚集索引扫描。它的性能非常好并且可以很好地扩展。
      【解决方案4】:

      您在 SAS 中执行此操作,那么为什么不使用数据步骤?

      data all;
        merge pool1(in = a) pool2(in = b keep = ID);
        by ID;
        if a and not(b);
      run;
      

      这要求两个数据集都按 ID 排序或索引。如果您在 B 中的每个 ID 有多个记录,那么我建议您先通过

      进行重复数据删除
      proc sort data = pool2 out = temp nodupkey;
        by id;
      run;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-29
        • 2011-01-13
        • 1970-01-01
        相关资源
        最近更新 更多