

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 设计 Amazon Redshift 查询的最佳实践
<a name="best-practices-designing-queries"></a>

本节概述设计查询的最佳实践。我们建议您遵循本节中的最佳实践，以实现最佳查询性能和效率。

## 避免使用 SELECT \* FROM 语句
<a name="select-from-statement"></a>

我们建议您避免使用 `SELECT * FROM` 语句。相反，请始终列出要分析的列。这样可以减少查询执行时间，并降低 Amazon Redshift Spectrum 查询的扫描成本。

**应避免的情况示例**

```
select * 
from sales;
```

**最佳实践示例**

```
select sales_date, sales_amt
from sales;
```

## 识别查询问题
<a name="query-issues"></a>

我们建议您检查 [STL\_ALERT\_EVENT\_LOG](https://docs.aws.amazon.com/redshift/latest/dg/r_STL_ALERT_EVENT_LOG.html) 视图，以识别并纠正查询中可能存在的问题。

## 获取有关查询的摘要信息
<a name="summary-info"></a>

我们建议您使用 [SVL\_QUERY\_SUMMARY](https://docs.aws.amazon.com/redshift/latest/dg/r_SVL_QUERY_SUMMARY.html) 和 [SVL\_QUERY\_REPORT](https://docs.aws.amazon.com/redshift/latest/dg/r_SVL_QUERY_REPORT.html) 视图来获取有关查询的摘要信息。您可以使用此信息来优化查询。

## 避免交叉联接
<a name="cross-joins"></a>

除非绝对有必要，否则建议避免使用交叉联接。如果没有联接条件，交叉联接会生成两个表的笛卡尔乘积。交叉联接通常作为嵌套循环联接（可能最慢的联接类型）运行。

**应避免的情况示例**

```
select c.c_name, 
          n.n_name 
from tpch.customer c, 
        tpch.nation n;
```

**最佳实践示例**

```
select c.c_name, 
           n.n_name 
from tpch.customer c, 
join tpch.nation n
  on n.n_nationkey = c.c_nationkey;
```

## 避免在查询谓词中使用函数
<a name="functions-query-predicates"></a>

我们建议您避免在查询谓词中使用函数。在查询谓词中使用函数可能会对性能产生负面影响，因为函数通常会给每行增加额外的处理开销，并减慢查询的整体执行速度。

**应避免的情况示例**

```
select sum(o_totalprice)
from tpch.orders
where datepart(year, o_orderdate) = 1992;
```

**最佳实践示例**

```
select sum(o_totalprice)
from tpch.orders
where o_orderdate between '1992-01-01' and '1992-12-31';
```

## 避免不必要的类型转换
<a name="cast-conversions"></a>

我们建议您避免对查询使用不必要的类型转换，因为转换数据类型需要时间和资源，并且会减慢查询的执行速度。

**应避免的情况示例**

```
select sum(o_totalprice)
from tpch.orders
where o_ordertime::date = '1992-01-01';
```

**最佳实践示例**

```
select sum(o_totalprice)
from tpch.orders
where o_ordertime between '1992-01-01 00:00:00' and '1992-12-31 23:59:59';
```

## 使用 CASE 表达式进行复杂聚合
<a name="case-expressions"></a>

我们建议您使用 [CASE 表达式](https://docs.aws.amazon.com/redshift/latest/dg/r_CASE_function.html)执行复杂聚合，而不是从同一个表多次选择。

**应避免的情况示例**

```
select sum(sales_amt) as us_sales
from sales
where country = 'US';

select sum(sales_amt) as ca_sales
from sales
where country = 'CA';
```

**最佳实践示例**

```
select sum(case when country = 'US' then sales_amt end) as us_sales,
           sum(case when country = 'CA' then sales_amt end) as ca_sales
from sales;
```

## 使用子查询
<a name="subqueries"></a>

如果查询中有一个表只用于谓词条件并且子查询返回的行数较少（少于 200 行），则我们建议您使用子查询。

**应避免的情况示例**

如果子查询返回的行数少于 200 行：

```
select sum(order_amt) as total_sales
from sales
where region_key IN
        (select region_key
         from regions
         where state = 'CA');
```

**最佳实践示例**

如果子查询返回的行数大于或等于 200 行：

```
select sum(o.order_amt) as total_sales
from sales o
join regions r
  on r.region_key = o.region_key
  and r.state = 'CA';
```

## 使用谓词
<a name="predicates"></a>

我们建议您使用谓词尽可能限制数据集。在 SQL 中使用谓词以筛选和限制查询中返回的数据。通过使用谓词指定条件，您可以根据指定的条件指定查询结果中必须包含哪些行。这样便可仅检索自己感兴趣的数据，并提高查询的效率和准确性。有关更多信息，请参阅 Amazon Redshift 文档中的[条件](https://docs.aws.amazon.com/redshift/latest/dg/r_conditions.html)。

## 添加谓词以筛选包含联接的表
<a name="filter-tables-joins"></a>

我们建议您添加谓词以筛选参与联接的表（即使谓词应用相同的筛选条件）。在 SQL 中使用谓词筛选包含联接的表，可以通过减少必须处理的数据量并减小中间结果集的大小来提高查询性能。通过在 `WHERE` 子句中指定联接操作的条件，查询执行引擎可以在联接前剔除不符合条件的行。这会生成更小的结果集并加快查询执行速度。

**应避免的情况示例**

```
select p.product_name, sum(o.order_amt)
from sales o
join product p
   on r.product_key = o.product_key
where o.order_date > '2022-01-01';
```

**最佳实践示例**

```
select p.product_name, sum(o.order_amt)
from sales o
join product p
  on p.product_key = o.product_key
  and p.added_date > '2022-01-01'
where o.order_date > '2022-01-01';
```

## 对谓词使用成本最低的运算符
<a name="least-expensive-operators"></a>

在谓词中，尽可能使用成本最低的运算符。[比较条件](https://docs.aws.amazon.com/redshift/latest/dg/r_comparison_condition.html)运算符优先于 [LIKE](https://docs.aws.amazon.com/redshift/latest/dg/r_patternmatching_condition_like.html) 运算符，而 `LIKE` 运算符仍优先于 [SIMILAR TO](https://docs.aws.amazon.com/redshift/latest/dg/pattern-matching-conditions-similar-to.html) 或 [POSIX](https://docs.aws.amazon.com/redshift/latest/dg/pattern-matching-conditions-posix.html) 运算符。

## 在 GROUP BY 子句中使用排序键
<a name="group-by-clauses"></a>

在 `GROUP BY` 子句中使用排序键，以便查询计划程序可以使用更高效的聚合。如果查询的 `GROUP BY` 列表只包含排序键列，并且其中一列也是分配键，则查询可能适合单阶段聚合。`GROUP BY` 列表中的排序键列必须包含第一个排序键，接下来按排序键顺序包含其他需要使用的排序键。

## 利用实体化视图
<a name="materialized-views"></a>

如果可能，请通过将复杂的代码替换为实体化视图来重写查询，这将显著提升查询的性能。有关更多信息，请参阅 Amazon Redshift 文档中的[在 Amazon Redshift 中创建实体化视图](https://docs.aws.amazon.com/redshift/latest/dg/materialized-view-overview.html)。

## 注意 GROUP BY 和 ORDER BY 子句中的列
<a name="group-by-order-by"></a>

如果同时使用 `GROUP BY` 和 `ORDER BY` 子句，请确保 `GROUP BY` 和 `ORDER BY` 子句中各列的顺序保持一致。`GROUP BY` 隐式要求数据已排序。如果您的 `ORDER BY` 子句不同，则必须对数据进行两次排序。

**应避免的情况示例**

```
select a, b, c, sum(d)
from a_table
group by b, c, a
order by a, b, c
```

**最佳实践示例**

```
select a, b, c, sum(d)
from a_table
group by a, b, c
order by a, b, c
```