查询溢出到磁盘

问题描述

我们有一个溢出到磁盘的查询(大约 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
);

没有索引,没有约束

谢谢,

解决方法

答案已经在你的问题中

没有索引,没有约束

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

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;