优化大型表上的 SQL 连接

Posted

技术标签:

【中文标题】优化大型表上的 SQL 连接【英文标题】:Optimizing an SQL join on large tables 【发布时间】:2012-07-10 21:32:10 【问题描述】:

我正在对 PostgreSQL 数据库上的一个大表(每天 7,000,000 条新行)运行 sql 查询集合,并且在第一个视图和现在创建表时遇到了一些性能问题。我使用的大多数命令都类似于以下查询:

CREATE TABLE events_tb AS

SELECT *

FROM
(SELECT column1, column2, column3, column4, column5
 FROM test_database_1
 WHERE column6 = 'value1'
   AND date_column > '2012-07-01'
   AND date_column < '2012-07-10'
) a

INNER JOIN ( SELECT DISTINCT column1 FROM test_database_2) b
        ON (a.column1 = b.column1);

有没有办法改进上述语句集合,以解决查询是针对非常大的表运行的事实?

【问题讨论】:

请告诉我们执行计划。最好作为explain analyze上传到explain.depesz.com 您提到了“语句集合”,但我只看到一个查询? 【参考方案1】:

这应该更简单更快:

CREATE TABLE events_tb AS
SELECT column1, column2, column3, column4, column5
FROM   test_database_1 t1
WHERE  column6 = 'value1'
AND    date_column > '2012-07-01'
AND    date_column < '2012-07-10'
AND    EXISTS (
    SELECT 1
    FROM   test_database_2 t2
    WHERE  t2.column1 = t1.column1
    );

您的方式会在新创建的表中包含两次column1,这将导致错误消息。

EXISTS semi-join 应该比 JOININ 表达式快,因为它可以在第一次找到时停止执行。这对于重复项特别有用 - 从查询中的 DISTINCT 来看,您似乎拥有重复项。

【讨论】:

【参考方案2】:

我对 PostgreSQL 的优化器一无所知,但您可以尝试将 INNER JOIN 替换为 IN (SELECT...) 结构:

CREATE TABLE events_tb AS

SELECT column1, column2, column3, column4, column5

FROM test_database_1

WHERE column6 = 'value1'
  AND date_column > '2012-07-01'
  AND date_column < '2012-07-10'
  AND column1 IN ( SELECT DISTINCT column1 FROM test_database_2 )

【讨论】:

由于您将其移至IN,因此不再需要distinct。这可能会改善或恶化性能,具体取决于数据的情况。 date_columncolumn6 有索引吗? IN (SELECT ...) 在 PostgreSQL 中通常不比 JOIN 快。

以上是关于优化大型表上的 SQL 连接的主要内容,如果未能解决你的问题,请参考以下文章

SQL - 连接表上的查询

SQL:同一表上的多个连接的性能

使用右表上的总和分组对多列进行 SQL 连接

Oracle查询转换之连接谓词推入

在 4 个表上的 sqlite 中完全外连接

同一张表上的多个连接:转换状态