---
schema_version: "1"
id: 1a9fc7105a4d0e4415dc027b29ff70e039e6c7dc2523ba2ba52abc5c1ea15cb8
title: 数据源和工作簿的 RLS 最佳实践
collection: tableau
version: current
locale: zh-cn
portal_url: https://docs.salesforce.com/tableau/current/zh-cn/server-linux/rls_bestpractices.md
canonical_url: https://help.tableau.com/current/server-linux/zh-cn/rls_bestpractices.htm
source_site: help.tableau.com
content_type: documentation
content_hash: dfbb7a9099543f44c271317f43e3edff06eb9c0009fe02315f77dbe6c757af4b
description: Understand best practices for row-level security with entitlement tables.
---
[跳转到主要内容](#main-content)

# 数据源和工作簿的 RLS 最佳实践

Tableau 中的行级安全性 (RLS) 是指限制特定用户可在工作簿中看到的数据行。这与 Tableau 权限不同，后者用于控制对内容和特性功能的访问。例如，权限控制用户是否可以对工作簿进行注释或编辑，而行级安全性使查看同一仪表板的两个用户能够仅查看允许每个用户查看的数据。

可通过多种方式在 Tableau 中实现 RLS。例如，您可以在数据源或工作簿级别设置 RLS，或者您可以使用具有数据策略的虚拟连接在连接级别设置 RLS（需要 Data Management）。有关备选方案的详细信息，请参见[Tableau 中的行级安全性选项概述](https://help.tableau.com/current/server-linux/zh-cn/rls_options_overview.htm)。

**注意**：本主题重点介绍数据源和工作簿的 RLS 最佳实践。有关本主题中概述的概念的更多深入示例，请参考白皮书 [Best Practices for Row Level Security with Entitlement Tables（适用于具有权利表的行级别安全性的最佳做法）](https://www.tableau.com/zh-cn/learn/whitepapers/row-level-security-entitlements-tables)或博客 _Tableau and Behold_ 上的 [How to Set Up Your Database for Row Level Security in Tableau（如何在 Tableau 中为行级安全性设置数据库）](https://tableauandbehold.com/2016/03/07/how-to-set-up-your-database-for-row-level-security-in-tableau/)。

## RLS 工作流程

对于实时连接和多表数据提取，基本 RLS 工作流为：

1. 通过登录到 Tableau Server 或 Tableau Cloud 来标识用户
    - 这需要每个用户不同的用户名和安全单点登录 （SSO）
    - 可以使用 Active Directory、LDAP 或 Tableau REST API 来同步用户名和建立权限
2. 从所有可能的数据权利中检索用户的数据权利集
    - 这需要一个可将权利链接到 Tableau 用户名的数据结构
3. 数据按该用户的权利进行筛选
    - 这通常需要在计算字段中使用用户函数
4. 已发布的筛选数据用于生成内容
    - 使用具有数据源筛选器的已发布（而不是嵌入式）数据源可确保无法通过下载工作簿或通过 Web 编辑工作簿来修改 RLS

联接、计算字段和筛选器的设置方式取决于数据的结构以及用户的管理方式。

## 权利表

可依据其对数据进行筛选的任何唯一属性组合都是一个权利。最常见的情况是，有单独的表用于指定权利本身并将这些权利映射到用户或用户角色。从性能角度来看，建议取消规范化，因为联接是高开销的操作。

权利视图（包括映射到用户或角色的权利）与数据联接。然后应用基于用户的数据源筛选器，作为 WHERE 子句，该子句仅为相关用户引入权限，从而引入适当的数据行。（查询优化应确保在联接处理时在查询之前进行筛选，以尽量减少数据重复。有关详细信息，请参见[性能和操作的处理顺序](#Performa)。）

### 权利表模型

通常，有两种表示权利的模型：

**完全映射到最深粒度级别**

- 为每个列完全定义权利。
- 映射表中有一行适用于用户具有的每个可能的权利。
- 此模型需要较少的联接子句。

**稀疏权利**

- 为每个层次结构级别定义权利，使用 NULL 表示“全部”状态。
- 映射表有一行适用于权利层次结构中的特定级别，这大大减少了层次结构中高级别用户的权利行数。
- 此模型需要更复杂的联接和筛选器。

### 用户和角色

权利的组合通常表示为_角色_，后者随后链接到多对多映射表中的用户。这允许轻松更改角色或从角色中移除用户，同时仍保留角色及其权利的记录。

或者，可以创建直接将用户分配给权利的多对多映射表，而不是联接角色表。这将需要更直接管理表中的值，但确实不需要联接。

**注意：**与角色或权利关联的用户值需要与 Tableau 站点上的用户名或全名匹配，以便利用 Tableau Desktop 中的用户功能。

### 联接

无论用于表示权利的模型如何，建议联接所有权利并将表映射到单个非规范化权利视图中。尽管一开始这将导致权利的“爆炸”（高度重复）版本，但用户的数据源筛选器将减少它。如果您计划使用数据提取，您也将需要此视图。

当一切都是分层的时，最深层粒度方法可能有性能优势 — 您只需在层次结构的最深层级别执行单个联接即可。仅当最低级别的所有属性都不同时，此方法才有效。如果可能存在重复（例如，多个区域中的中央子区域），则需要联接所有列，以实现不同键值的效果。

实际的详细信息及其性能特征取决于数据系统，需要进行测试。例如，使用单个键可能会提高性能，因为联接仅在一列上执行，但在考虑其他因素时，为所有列正确编制索引可能会提供相同的性能。

## 实现行级安全性

### 最深的粒度

创建映射权利的去规范化视图后，将会在视图和 Tableau 数据连接对话框中的视图之间设置内部联接。数据可以保留在传统的星型架构中。或者，维度表和事实表可以一起具体化为两个视图。多表数据提取将生成数据提取表以匹配联接，因此创建两个视图将简化生成的数据提取。SQL 将遵循以下基本模式：

SELECT \* 
FROM data d INNER JOIN entitlements e ON
d.attribute\_a = e.attribute\_a AND 
d.attribute\_b = e.attribute\_b AND ... 
WHERE e.username = USERNAME()

### 稀疏权利

如果您的权利更类似于稀疏权利模型，则由于 NULL 值的原因，将数据联接到权利的自定义 SQL 将稍微复杂一些。从概念上讲，它看起来如下所示： 

SELECT \*
FROM data d 
INNER JOIN entitlements e ON
(e.region\_id = d.region\_id OR ISNULL(e.region\_id) AND
(e.sub\_region\_id = d.sub\_region\_id OR ISNULL(e.sub\_region\_id) AND
(e.country\_id = d.country\_id OR ISNULL(e.country\_id)

无需使用自定义 SQL，即可在 Tableau Desktop 中使用交叉联接和其他筛选器来完成此操作。在联接对话框的两侧创建联接计算，该计算仅由整数 1 组成，并将其设置为相等。这将数据表中的每一行与权利表中的每一行联接。

然后，您需要计算（或单个计算）来考虑层次结构中的级别。例如，您可能有采用以下格式的若干计算：`[region_id] = [region_id (Entitlements View)] OR ISNULL([region_id (Entitlements View)]`

或者，您可能有将所有级别合并在一个中的合并计算：

(\[region\_id\] = \[region\_id (Entitlements View)\] OR ISNULL(\[region\_id (Entitlements View)\])
AND
(\[sub\_region\_id\] = \[sub\_region\_id (Entitlements View)\] OR ISNULL(\[sub\_region\_id (Entitlements View)\])
AND
(\[country\_id\] = \[country\_id (Entitlements View)\] OR ISNULL(\[country\_id (Entitlements View)\])

ISNULL 函数将任何权利列与其他列中的所有项匹配。与 RLS 一样，这些计算应添加为数据源筛选器。

### 数据源筛选器

对于这两种方法，一旦权利与数据正确联接，就需要设置筛选器以限制特定用户的数据。应使用用户函数创建计算字段。例如，对 Username 字段中列出的用户是否与登录到 Tableau 站点的用户的用户名相同进行简单的布尔比较：`[Username] = USERNAME()`

此计算应用作数据源筛选器（选中 TRUE）。

如果数据源已嵌入，并且用户具有 Web 编辑或下载工作簿的权限，则 RLS 不存在，因为可以轻松移除强制该数据源的筛选器。Tableau 数据源应单独发布，而不是嵌入到工作簿中。

### 具有最深粒度的所有访问权限

还有一种常见情况，即组织内有两个访问权限级别：能够查看所有内容（“所有访问权限”）的人员，或具有某种合理可定义的权利子集的人员。这在嵌入式应用程序中最为常见 — 托管数据的组织可以查看所有内容，但每个客户只能查看自己的数据。在这种情况下，您需要一种方法来针对“所有访问权限”用户返回完整数据，同时为所有其他用户保留最深粒度的联接。

对于此方法，您将使用 Tableau 组在联接条件中使用计算来创建覆盖。

1. 为应查看所有数据的用户创建组（此处称为“所有访问权限”）
2. 从事实视图中，创建具有两个联接条件的左联接
    - 第一个联接条件应位于表示最深层粒度的列上
    - 第二个联接条件应该是两个计算：
        - 在左侧（事实视图），为计算输入 `True`
        - 在右侧（权利视图），计算应为：`IF ISMEMBEROF('All Access') THEN False ELSE True END`
3. 在工作表上，创建一个结构如下的计算：`[Username] = USERNAME() OR ISMEMBEROF(['All Access'] ([Entitlements View)])`
4. 在用户名计算上创建数据源筛选器

如果用户是“所有访问权限”组的成员，则联接将成为 `True = False` 上的左联接。这意味着权利视图中根本没有匹配项，因此在返回的整个事实视图中，权利视图中的列为 NULL（零重复）。如果用户不是“所有访问权限”组的成员，则 `True = True` 联接条件不会更改任何内容，并且联接将按预期运行。

当组重写工作时，用作数据源筛选器的用户计算对所有行都为 true，或者它将筛选到层次结构中用户的最深粒度。

### 性能和操作的处理顺序

在 Tableau Desktop、Tableau Server 或 Tableau Cloud 中查看可视化项时，Tableau 会向 RDBMS 发送优化的查询，然后 RDBMS 处理查询并将结果发送回 Tableau 以使用生成的数据呈现可视化项。执行联接、计算和筛选器的操作顺序取决于查询优化器以及查询的执行方式。

#### 实时连接

在 Tableau 中使用与数据源的实时连接时，查询执行的性能取决于查询优化器，该优化器将传入的 SQL 转换为检索数据的有效计划。

处理查询的方法有两种：

1. 将权利行筛选到用户，然后联接到事实表
2. 将权利联接到事实表，然后筛选到用户的行

在理想情况下，查询优化器将确保数据库通过_筛选然后联接_来处理查询。 如果用户有权拥有所有内容，这意味着处理的最大行数将是数据表中的行数。

如果数据库通过_联接然后筛选_处理查询，则数据可能会重复。 处理的最大行数是有权查看该特定行的用户数乘以数据表中的每一行。

如果发生第二种情况，将很清楚：您的查询需要很长时间才能完成，您会收到错误，或者数据库中存在性能问题的迹象。您的数据总量将呈指数级增长，这可能导致后端系统过度紧张。

#### 数据提取

当 Tableau 中的数据源是实时连接时，Tableau 会向 RDBMS 发送呈现特定可视化项或仪表板所需的每个查询。当数据源是数据提取时，从基础数据源查询数据的过程仅在创建和刷新数据提取时发生。所有可视化的单个查询都由数据提取文件中的数据提取引擎回答。

生成单个表数据提取时也存在相同的操作顺序问题。但是，“爆炸”将发生在基础数据源和生成的数据提取本身中。

## 数据提取注意事项

从 Tableau 2018.3 开始，数据引擎可以创建多表数据提取，并且可以按上述方式实施 RLS。使用多个表数据提取减少了生成具有多对多关系的数据提取所需的时间，因为它没有实现联接。

数据提取应使用_数据对象_和_权利对象_生成。 这是数据提取中最简单的存储，可获得最佳性能。

- _数据对象_是表、视图或自定义 SQL 查询，表示事实表和必要维度表的去规范化组合
- _权利对象_是去规范化的表、视图或自定义 SQL 查询，包含在最精细的级别筛选数据所需的任何权利，该对象需要：
    - 与 Tableau Server 或 Tableau Cloud 中的确切用户名匹配的用户名列
    - 数据对象每个最精细权利的行

此格式采用上述最深粒度方法排列。多表数据提取使用相同的方法，但需要注意的是，只有两个正在联接的对象，并且已在对象中应用了任何特定于字段的筛选。

由于多表数据提取禁用了数据提取筛选器，因此可以在数据源中连接到的视图或表中进行筛选，或在 Tableau 数据连接对话框中定义自定义 SQL 对象中的筛选器。

**注意：**与实时连接一样，如果数据源已嵌入，并且用户具有 Web 编辑或下载工作簿的权限，则 RLS 不存在，因为可以轻松移除强制该数据源的筛选器。数据提取应单独发布，而不是嵌入到工作簿中。

### 单表数据提取

仅当使用 2018.3 之前的 Tableau 版本时，才建议使用以下方法 — 如果可用，则最好使用多表数据提取。

单表数据提取在构造 Tableau 数据源时将实现生成的任何联接，并通过一个查询将所有内容存储为单个表，其结果在数据提取文件中的单个表中转换。这种去规范化会造成大量数据重复的风险，因为分配给多个权利或用户的每一行都会由于多对多关系而重复。

为了防止这种重复，请执行以下操作：

1. 创建包含该权利用户名的安全用户字段
    - 例如，值可以是“bhowell\_mosterheld\_rdugger”
2. 使用 Tableau 中的 CONTAINS（） 函数正确识别单个用户
    - 例如，`CONTAINS([Security Users Field], USERNAME())`

这种方法显然有一些注意事项。它要求您从行中的权利转到使用 SQL 正确分隔的单个列，并且该列只能包含这么多字符。部分匹配可能会带来麻烦，您需要使用在 ID 本身中永远无效的分隔符。尽管它在 Tableau 数据引擎中性能出色，但作为字符串计算，对于大多数数据库来说，速度会很慢。这将限制您切换回实时连接的能力。

或者，您可以根据“角色”或权利级别使用不同的数据提取，以便数据提取中仅包含适合该人员或级别的数据，但这需要进程来适当许可和利用 Tableau Server 内的模板发布，通常通过 API 进行。

## 使用数据库中的内置行级安全性

许多数据库都有内置 RLS 的机制。如果您的组织已努力在数据库中构建行级安全性，则可以利用现有的 RLS。实现一个内置的 RLS 模型并不一定比在头脑中构建它更容易或更好：当组织已经对这些技术进行了投资，并且希望利用投资时，通常会利用这些技术。使用内置 RLS 的主要优点是，它允许管理员在一个位置，即在管理员数据库中实现和控制其数据安全策略。有关详细信息，请参见[数据库中的行级安全性](https://help.tableau.com/current/server-linux/zh-cn/rls_datasource.htm)。