我有一张非常大的桌子" event"在Redshift和一个小得多的桌子" d_date"代表日期。 Redshift将在"事件"上运行全表扫描。对于下面的SQL,除非我取消注释注释部分。表事件将date_id作为其排序键。
为什么Redshift没有发现它首先扫描d_date然后通过匹配值来限制事件表扫描要便宜得多?
select d_date.date_id, count(*)
from d_date
join event on d_date.date_id = event.date_id
where d_date.sqldate > '2016-06-03'
/* without this the query will do a full table scan and run very slow */
/* and d_date.date_id > 20160603 */
group by 1;
这是EXPLAIN输出:
QUERY PLAN
XN HashAggregate (cost=19673968.12..19673971.77 rows=1460 width=4)
-> XN Hash Join DS_DIST_ALL_NONE (cost=78.63..18758349.28 rows=183123769 width=4)
Hash Cond: ("outer".date_id = "inner".date_id)
-> XN Seq Scan on event (cost=0.00..7523125.76 rows=752312576 width=4)
-> XN Hash (cost=74.98..74.98 rows=1460 width=4)
-> XN Seq Scan on d_date (cost=0.00..74.98 rows=1460 width=4)
Filter: (sqldate > '2016-06-03'::date)
在部分取消注释的情况下,表格阶段将显示为:
-> XN Seq Scan on event (cost=0.00..928.32 rows=74266 width=4)
我有两个表的VACUUMed和ANALYZEd,我设置了主键和外键。
答案 0 :(得分:4)
Amazon Redshift文档专门针对Amazon Redshift Best Practices for Designing Queries中的这一主题:
如果可能,请使用基于查询中最大表的主排序列的WHERE子句来限制数据集。然后,查询计划程序可以使用行顺序来帮助确定哪些记录符合条件,因此它可以跳过扫描大量磁盘块。如果没有这个,查询执行引擎必须扫描整个表。
添加谓词以过滤参与连接的表,即使谓词应用相同的过滤器也是如此。查询返回相同的结果集,但Amazon Redshift能够在扫描步骤之前过滤连接表,然后可以有效地跳过这些表中的扫描块。
例如,假设您要加入
SALES
和LISTING
以查找12月之后列出的门票的门票销售,按卖家分组。两个表都按日期排序。以下查询将表格加入其公用密钥,并过滤大于12月1日的listing.listtime
值:
select listing.sellerid, sum(sales.qtysold)
from sales, listing
where sales.salesid = listing.listid
and listing.listtime > '2008-12-01'
group by 1 order by 1;
WHERE子句不包含
sales.saletime
的谓词,因此强制执行引擎扫描整个SALES
表。如果您知道过滤器会导致参与连接的行数减少,那么也要添加该过滤器。以下示例显着缩短了执行时间:
select listing.sellerid, sum(sales.qtysold)
from sales, listing
where sales.salesid = listing.listid
and listing.listtime > '2008-12-01'
and sales.saletime > '2008-12-01'
group by 1 order by 1;