查询溢出到磁盘

Posted

技术标签:

【中文标题】查询溢出到磁盘【英文标题】:Query spilling to disk 【发布时间】:2021-06-15 17:48:58 【问题描述】:

我们有一个溢出到磁盘的查询(大约 1 TB!),代码如下:

WITH q (year,quarter) AS ( SELECT * FROM temp.quarters) SELECT *,
(SELECT price FROM prices WHERE EXTRACT(QUARTER FROM
pricing_date::TIMESTAMP) = q.quarter AND EXTRACT(YEAR FROM
pricing_date::TIMESTAMP) = q.year ORDER BY pricing_date LIMIT 1) FROM
q ORDER BY q.year,q.quarter

价格表有数百万行,有没有办法改进这个查询,使它不会溢出太多?我们认为这可能是因为我们使用的是“With”子句而不是临时表?

下表定义:

CREATE TABLE public.record_pricing (
    record_id int8 NOT NULL,
    pricing_date date NOT NULL,
    price numeric(26,10) NOT NULL,
    )
WITH (
    appendonly=true
);

没有索引,没有约束

谢谢,

【问题讨论】:

您能告诉我们 EXPLAIN (ANALYZE, BUFFERS) 的结果吗?你能告诉我们你的表和索引定义吗?没有这些信息,几乎不可能为您提供帮助。 没问题,我正在运行它,我会尽快将它发布在这里 您使用的是哪个 Postgres 版本? 我们使用的是 9.4.24,它是一个 Greenplum DB 然后尝试删除 CTE。 (这并不是真正需要的开始)。 【参考方案1】:

答案已经在你的问题中了

没有索引,没有约束

为了在如此大的表中缩短查询时间,索引的使用势在必行。尝试将部分索引添加到您的表中,以便查询计划者事先知道在哪里可以找到年份和季度,例如

CREATE INDEX idx_pricing_quarter ON record_pricing (EXTRACT(QUARTER FROM pricing_date::TIMESTAMP));
CREATE INDEX idx_pricing_year ON record_pricing (EXTRACT(YEAR FROM pricing_date::TIMESTAMP));

.. 甚至

CREATE INDEX idx_pricing_year_quarter ON record_pricing 
  (EXTRACT(QUARTER FROM pricing_date::TIMESTAMP) , 
   EXTRACT(YEAR FROM pricing_date::TIMESTAMP));

您可能还想考虑为pricing_date 编制索引,看看documentation

CREATE INDEX idx_pricing_date ON record_pricing (pricing_date);

请注意,索引可能会减慢您表中的INSERTS!但由于它很可能是一个数据仓库,所以这可能不是问题。

之后,您的查询应该会变得更快。查看您的查询是否正确使用索引的最佳方法是EXPLAIN 它。使用它,您会看到自己的改进。

顺便说一句,CTE 不是这里的问题,因为它是在一个大概很小的表 temp.quartes 中进行全面扫描,但如果你想摆脱它,请尝试:

SELECT q.year,q.quarter,
 (SELECT price 
  FROM record_pricing 
  WHERE EXTRACT(QUARTER FROM pricing_date::TIMESTAMP) = q.quarter AND 
        EXTRACT(YEAR FROM pricing_date::TIMESTAMP) = q.year
  ORDER BY pricing_date LIMIT 1)
FROM quarters q;

【讨论】:

以上是关于查询溢出到磁盘的主要内容,如果未能解决你的问题,请参考以下文章

鉴于我将 DataBag 溢出到磁盘,为啥此 Pig UDF 会导致“错误:Java 堆空间”?

Pandas to PySpark给出OOM错误而不是溢出到磁盘[重复]

找不到开发人员磁盘映像堆栈溢出 xcode 7.2,iOS 9.3.1 [重复]

Spark:随机写入、随机溢出(内存)、随机溢出(磁盘)之间的区别?

记一次java内存溢出的解决过程

应该在没有磁盘容器的情况下使用 Berkeley DB XML?