

 从补丁 198 开始，Amazon Redshift 将不再支持创建新的 Python UDF。现有的 Python UDF 将继续正常运行至 2026 年 6 月 30 日。有关更多信息，请参阅[博客文章](https://www.amazonaws.cn/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)。

# RLS 性能最佳实践
<a name="t_rls_performance"></a>

以下是确保 Amazon Redshift 在受 RLS 保护的表上能够获得更高性能的最佳实践。

## 运算符和函数的安全性
<a name="t_rls_safe_operators"></a>

当查询受 RLS 保护的表时，使用某些运算符或函数可能会导致性能下降。对于查询受 RLS 保护的表，Amazon Redshift 会将运算符和函数分类为安全或不安全。如果根据输入，函数或运算符没有任何可观察到的副作用，则该函数或运算符将被分类为 RLS 安全。特别是，RLS 安全的函数或运算符不能是以下情况之一：
+ 输出输入值，或任何依赖于输入值的值，无论是否显示错误消息。
+ 失败或返回依赖于输入值的错误。

RLS 不安全的运算符包括：
+ 算术运算符：\+、-、/、\*、%。
+ 文本运算符：LIKE 和 SIMILAR TO。
+ 一些强制类型转换运算符。请注意，某些强制类型转换被归类为安全的转换，包括日期转换为时间戳和时间戳转换为日期、整数拓宽强制转换（例如 INT2 转换为 INT8 或 INT4 转换为 INT8）以及整数转换为文本。
+ UDF。

使用以下 SELECT 语句以检查运算符和函数的安全性。

```
SELECT proname, proc_is_rls_safe(oid) FROM pg_proc;
```

在规划对受 RLS 保护的表进行查询时，Amazon Redshift 将对包含 RLS 不安全运算符和函数的用户谓词的评估顺序施加限制。在查询受 RLS 保护的表时，引用 RLS 不安全运算符或函数的查询可能会导致性能下降。当 Amazon Redshift 无法将 RLS 不安全谓词向下推送到基表扫描以利用排序键时，性能可能会显著下降。为了获得更高性能，请避免使用利用排序键的 RLS 不安全谓词进行的查询。要验证 Amazon Redshift 是否能够向下推送运算符和函数，您可以将 EXPLAIN 语句与系统权限 EXPLAIN RLS 结合使用。

### 有条件安全的函数
<a name="t_rls_conditional_safety"></a>

一些函数通常被归类为不安全，但是当特定的参数是常量值（字面值，而不是列引用）时，这些函数就会成为安全函数。当相关参数为常量时，Amazon Redshift 可以将这些谓词下推到基表扫描，从而提高查询性能。

例如，`DATE_TRUNC('day', timestamp_col)` 是有条件安全的，因为 `'day'` 是常量字面值。但是，`DATE_TRUNC(datepart_col, timestamp_col)` 不是有条件安全的，因为 `datepart_col` 是列引用。

下表列出了有条件安全的函数的类别，以及哪些参数必须为常量才能使得函数被视为安全。


| 函数类别 | 函数 | 必须为常数的参数 | 
| --- | --- | --- | 
| DATE\_TRUNC | DATE\_TRUNC(datepart, timestamp)、DATE\_TRUNC(datepart, timestamptz) | datepart（第一个参数） | 
| EXTRACT/DATE\_PART | timestamp、timestamptz、date、time、timetz、interval 和 datetime 类型的 EXTRACT(field FROM source)、DATE\_PART(field, source) | field（第一个参数） | 
| DATEDIFF | timestamp 和 time 类型的 DATEDIFF(datepart, start, end) | datepart（第一个参数） | 
| TO\_CHAR | TO\_CHAR(timestamp, format)、TO\_CHAR(timestamptz, format) | format（第二个参数） | 
| CONVERT\_TIMEZONE | CONVERT\_TIMEZONE(source\_tz, target\_tz, timestamp)、CONVERT\_TIMEZONE(target\_tz, timestamp) | timezone 参数 | 
| LEFT/RIGHT | LEFT(string, length)、RIGHT(string, length) | length（第二个参数） | 
| SUBSTRING | text、bytea 和 varbyte 类型的 SUBSTRING(string, start, length) | length（第三个参数） | 
| SPLIT\_PART | SPLIT\_PART(string, delimiter, part) | part（第三个参数） | 

使用以下 SELECT 语句检查哪些函数是有条件安全的函数以及哪些参数位置必须是常量。

```
SELECT proname, proc_is_rls_conditionally_safe(oid) FROM pg_proc
WHERE proc_is_rls_conditionally_safe(oid) IS NOT NULL;
```

函数会返回一个以 0 为起始索引的参数位置数组，这些参数必须是常量；如果函数不是有条件安全的，则返回 NULL。

## 结果缓存
<a name="t_rls_result_cache"></a>

为了缩短查询运行时间并提高系统性能，Amazon Redshift 在领导节点的内存中缓存特定查询类型的结果。

在满足未受保护的表的所有条件并且满足以下所有条件时，Amazon Redshift 会将缓存的结果用于新查询来扫描受 RLS 保护的表：
+ 未曾修改策略中的表或视图。
+ 策略不使用在每次运行时必须求值的函数，如 GETDATE 或 CURRENT\_USER。

为了获得更高性能，请避免使用不满足前述条件的策略谓词。

有关 Amazon Redshift 中的结果缓存的更多信息，请参阅[结果缓存](c_challenges_achieving_high_performance_queries.md#result-caching)。

## 复杂策略
<a name="t_rls_complex_policies"></a>

为了获得更高性能，请避免将复杂策略与联接多个表的子查询配合使用。

## 使用常量参数以实现更好的下推
<a name="t_rls_constant_args"></a>

在对受 RLS 保护的表的查询中使用 DATE\_TRUNC、EXTRACT、DATEDIFF、TO\_CHAR、CONVERT\_TIMEZONE、LEFT、RIGHT、SUBSTRING 或 SPLIT\_PART 等函数时，请为参数使用常量字面值参数而不是列引用，来控制错误行为。这使得 Amazon Redshift 可以将这些函数归类为安全函数，并将谓词下推到基表扫描，这可以显著提高性能。

例如，以下查询允许谓词下推，因为 datepart 参数是一个常量：

```
SELECT * FROM rls_protected_table
WHERE DATE_TRUNC('month', event_date) = '2024-01-01';
```

以下查询防止谓词下推，因为 datepart 参数是列引用：

```
SELECT * FROM rls_protected_table
WHERE DATE_TRUNC(datepart_col, event_date) = '2024-01-01';
```

有关有条件安全的函数以及哪些参数必须为常量的完整列表，请参阅[有条件安全的函数](#t_rls_conditional_safety)。