设计查询的 Amazon Redshift 最佳实践
要最大程度地提高查询性能,请在创建查询时遵循这些建议:
-
根据最佳实践设计表,为查询性能提供坚固的基础。有关更多信息,请参阅 设计表的 Amazon Redshift 最佳实践。
-
避免使用
select *
。仅包含您需要的列。 -
使用 CASE 条件表达式 执行复杂聚合,而不是从同一表多次选择。
-
除非绝对必要,否则,不要使用交叉联接。这些没有联接条件的联接会导致两个表的笛卡尔积。交叉联接通常作为嵌套循环联接运行,这是最慢的联接类型。
-
如果查询中有一个表只用于谓词条件并且子查询返回的行数较少 (不足 200 行),可以使用子查询。下面的示例使用子查询来避免联接 LISTING 表。
select sum(sales.qtysold) from sales where salesid in (select listid from listing where listtime > '2008-12-26');
-
使用谓词尽可能限制数据集。
-
在谓词中,尽可能使用成本最低的运算符。比较条件 运算符优先于 LIKE 运算符。LIKE 运算符优先于 SIMILAR TO 或 POSIX 运算符。
-
避免在查询谓词中使用函数。如果使用函数,则需要大量的行来解析查询的中间步骤,从而增加查询成本。
-
如果可能,请使用 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;
-
在 GROUP BY 子句中使用排序键,以便查询计划程序可以使用更高效的聚合。如果查询的 GROUP BY 列表只包含排序键列,并且其中一列也是分配键,则查询可能适合单阶段聚合。GROUP BY 列表中的排序键列必须包含第一个排序键,然后按排序键顺序包含其他需要使用的排序键。例如,可以使用第一个排序键,第一个和第二个排序键,第一个、第二个和第三个排序键,依此类推。不能使用第一个和第三个排序键。
您可以通过在查询的聚合步骤中运行 EXPLAIN 命令和查找
XN GroupAggregate
来确认使用单阶段聚合。 -
如果同时使用 GROUP BY 和 ORDER BY 子句,两个子句中各列的顺序必须相同。也就是,使用下面的方法。
group by a, b, c order by a, b, c
不要使用以下方法。
group by b, c, a order by a, b, c