0

谁能告诉我以下哪一项更有效?我有数千万行要处理,性能至关重要。

在第二个示例中,table0是一个临时表,它的创建似乎比第一个示例中的 table0 快得多。(为什么?)在第一个示例中我不能使用临时表,因为在创建表之前无法声明变量行。(table0保存原始表的所有不同行,下面的代码中没有显示。)

我想在第二个示例中为 、 和 of 创建哈希索引是个好主意blah2,尽管写入blah3表需要更长的时间。blah4blah5table1


FOR row IN SELECT * FROM table0
LOOP
  IF NOT EXISTS (SELECT 1 FROM table1
                   WHERE blah2 = row.blah2 AND blah3 = row.blah3
                     AND blah4 = row.blah4 AND blah5 = row.blah5) THEN
    INSERT INTO table2
      (blah0, blah1, blah2, blah3, blah4, blah5)
      VALUES (row.blah0, row.blah1, row.blah2, row.blah3, row.blah4, row.blah5);
  END IF;
END LOOP;

INSERT INTO table2
  (blah0, blah1, blah2, blah3, blah4, blah5)
  SELECT blah0, blah1, blah2, blah3, blah4, blah5 FROM table0
    WHERE NOT EXISTS
      (SELECT 1 FROM table1
         WHERE table1.blah2 = table0.blah2
           AND table1.blah3 = table0.blah3
           AND table1.blah4 = table0.blah4
           AND talbe1.blah5 = table0.blah5);
4

1 回答 1

1

问题

在第二个示例中,table0 是一个临时表,它的创建似乎比第一个示例中的 table0 快得多。(为什么?)

临时表通常比常规表快得多,因为它们的内容不会持久化到磁盘。当您创建一个时,您仍然有少量磁盘活动,因为系统目录接收条目。

一旦临时缓冲区用完,临时表的性能就会下降,因为系统开始将页面换出到磁盘。您可以temp_buffers在会话开始时设置为临时表提供更多 RAM。此相关答案中的更多详细信息。

如果最终您想将结果保存在某个地方,那么您不妨在第二个示例中立即使用常规表。

第一个示例也慢得多,因为循环单个行通常比使用 SQL 命令的基于集合的操作昂贵得多

在第一个示例中我无法使用临时表,因为在创建表之前无法声明变量行。(table0 包含原始表的所有不同行,下面的代码中没有显示。)

好吧,在创建表之前,您不能在函数中使用行类型。但是您可以只使用匿名记录:

DECLARE
   rec record;
BEGIN
   FOR rec IN SELECT * FROM table0 ...

替代解决方案

但是无论如何,您的第一种方法都不好。你的第二种方法看起来很好。应该是最快的方法。另一种选择是:

INSERT INTO table2 (blah0, blah1, blah2, blah3, blah4, blah5)
SELECT t0.blah0, t0.blah1, t0.blah2, t0.blah3, t0.blah4, t0.blah5
FROM   table0 t0
LEFT   JOIN table1 t1 USING (blah2, blah3, blah4, blah5)
WHERE  t1.t1_id IS NULL -- or any other column defined NOT NULL

如果您有重复的 in 条目(blah2, blah3, blah4, blah5)table1那么您的查询EXISTS可能会更快。否则这个带有LEFT JOIN/的IS NULL可能会排在首位。

索引和测试

当然,in 上的索引(blah2, blah3, blah4, blah5)会有table1很大帮助——增加了在 .in 中写入操作的一些成本table1。让它成为一个普通的 b-tree 索引(就像@Craig 在评论中已经建议的那样),但我会选择一个multi-column index。这种情况下更便宜,更快!

EXPLAIN ANALYZE正如@Craig 在评论中建议的那样用于测试性能 - 或者只是首先EXPLAIN(没有ANALYZE),因为你的表似乎很大并且EXPLAIN ANALYZE假执行它以获得实时。

于 2012-10-12T17:48:11.753 回答