
# DWS如何实现业务隔离
#### 业务隔离
DWS中可以使用Database和Schema实现业务的隔离，区别在于：
- Database之间无法直接互访，通过连接隔离实现彻底的权限隔离。各个Database之间共享资源极少，可实现连接隔离、权限隔离等。
- Schema隔离的方式共用资源较多，可以通过GRANT与REVOKE语法便捷地控制不同用户对各Schema及其下属对象的权限，从而赋予业务更多的灵活性。
 
从便捷性和资源共享效率上考虑，推荐使用Schema进行业务隔离。建议系统管理员创建Schema和Database，再赋予相关用户对应的权限。
图1权限控制   
![](https://support.huaweicloud.com/dws_faq/figure/zh-cn_image_0000001389253162.png "点击放大")
#### DATABASE
数据库Database是数据库对象的物理集合，不同Database之间资源完全隔离（除部分共享对象之外）。即Database是对业务的物理隔离，不同Database之间的对象不能相互访问。比如在Database A中无法访问Database B中的对象。因此登录集群的时候必须指定要连接的Database。
#### SCHEMA
数据库里面通过Schema把数据库对象进行逻辑划分，在Database中，通过Schema实现对数据库对象的逻辑隔离。
通过权限管理实现在同一个session下对不同Schema下对象的访问和操作权限。Schema下则是各种应用程序会接触到的对象，比如表，索引，数据类型，函数，操作符等。
同一个Schema下，不能存在同名的数据库对象；但是如果在不同Schema下，对象名可以重复。
```
gaussdb=> CREATE SCHEMA myschema;
CREATE SCHEMA
gaussdb=> CREATE SCHEMA myschema_1;
CREATE SCHEMA
gaussdb=> CREATE TABLE myschema.t1(a int, b int) DISTRIBUTE BY HASH(b);
CREATE TABLE
gaussdb=> CREATE TABLE myschema.t1(a int, b int) DISTRIBUTE BY HASH(b);
ERROR:  relation "t1" already exists
gaussdb=> CREATE TABLE myschema_1.t1(a int, b int) DISTRIBUTE BY HASH(b);
CREATE TABLE
```
Schema实现了对业务的逻辑划分，反过来这些业务对象也对Schema形成一种依赖关系，因此当Schema下存在对象时，删除Schema的时候会报错，并提示具体的依赖信息。
```
gaussdb=> DROP SCHEMA myschema_1;
ERROR: cannot drop schema myschema_1 because other objects depend on it 
Detail: table myschema_1.t1 depends on schema myschema_1 
Hint: Use DROP ... CASCADE to drop the dependent objects too.
```
当删除Schema的时候加上CASCADE选项，把Schema以及依赖此Schema的选项连带删除。
```
gaussdb=> DROP SCHEMA myschema_1 CASCADE;
NOTICE:  drop cascades to table myschema_1.t1
gaussdb=> DROP SCHEMA
```
#### USER/ROLE
用户或角色是数据库服务器(集群)全局范围内的权限控制系统，是集群业务的所有者和执行者，用于各种集群范围内所有的对象权限管理。因此角色不特定于某个单独的数据库，但角色登录集群的时候必须要显式指定登录的用户名，以保证当前连接执行的操作者的透明性。同时数据库也会通过权限管理限定用户的访问和操作权限。
用户是权限的最终体现者，所有的权限管理最终都体现在用户对数据库对象的操作权限是否被允许。
#### 权限管理
DWS中的权限管理分为三种场景：
- 系统权限 系统权限又称为用户属性，包括SYSADMIN、CREATEDB、CREATEROLE、AUDITADMIN和LOGIN。
  系统权限一般通过CREATE/ALTER ROLE语法来指定。其中，SYSADMIN权限可以通过GRANT/REVOKE ALL PRIVILEGES授予或撤销。但系统权限无法通过ROLE和USER的权限被继承，也无法授予PUBLIC。
  

- 用户权限 将一个角色或用户的权限授予一个或多个其他角色或用户。在这种情况下，每个角色或用户都可视为拥有一个或多个数据库权限的集合。
  当声明了WITH ADMIN OPTION时，被授权的用户可以将该权限再次授予其他角色或用户，以及撤销所有由该角色或用户继承到的权限。当授权的角色或用户发生变更或被撤销时，所有继承该角色或用户权限的用户拥有的权限都会随之发生变更。
  数据库系统管理员可以给任何角色或用户授予/撤销任何权限。拥有CREATEROLE权限的角色可以赋予或者撤销任何非系统管理员角色的权限。
  

- 数据对象权限 将数据库对象（表和视图、指定字段、数据库、函数、模式等）的相关权限授予特定角色或用户。GRANT命令将数据库对象的特定权限授予一个或多个角色。这些权限会追加到已有的权限上。
  
 
#### SCHEMA隔离应用示例
示例一：
Schema的owner默认拥有该Schema下对象的所有权限，包括删除权限；Database的owner默认拥有该Database下对象的所有权限，包括删除权限。因此建议对Database和Schema的创建要作比较严格的控制，一般建议使用管理员创建Database和Schema，然后把相关的权限控制赋予业务用户。
1. dbadmin在数据库testdb下把创建Schema的权限赋予普通用户user_1。 
   ```
   testdb=> GRANT CREATE ON DATABASE testdb TO user_1;
   GRANT
   ```
   
   
2. 切换到普通用户user_1。 
   ```
   testdb=> SET SESSION AUTHORIZATION user_1 PASSWORD '********';
   SET
   ```
   用户user_1在数据库testdb下创建名为myschema_2的Schema。
   ```
   testdb=> CREATE SCHEMA myschema_2;
   CREATE SCHEMA
   ```
   
   
3. 切换到管理员dbadmin。 
   ```
   testdb=> RESET SESSION AUTHORIZATION;
   RESET
   ```
   管理员dbadmin在模式myschema_2下创建表t1。
   ```
   testdb=> CREATE TABLE myschema_2.t1(a int, b int) DISTRIBUTE BY HASH(b);
   CREATE TABLE
   ```
   
   
4. 切换到普通用户user_1。 
   ```
   testdb=> SET SESSION AUTHORIZATION user_1 PASSWORD '********';
   SET
   ```
   普通用户user_1删除管理员dbadmin在模式myschema_2下创建的表t1。
   ```
   testdb=> drop table myschema_2.t1;
   DROP TABLE
   ```
   
   
示例二：
因为Schema的逻辑隔离的功能，访问数据库对象实际上要通过Schema和具体对象的两层校验。
1. 把表myschema.t1的权限赋予用户user_1。 
   ```
   gaussdb=> GRANT SELECT ON TABLE myschema.t1 TO user_1;
   GRANT
   ```
   
   
2. 切换到用户user_1。 
   ```
   SET SESSION AUTHORIZATION user_1 PASSWORD '********';
   SET
   ```
   查询表myschema.t1。
   ```
   gaussdb=> SELECT * FROM myschema.t1;
   ERROR:  permission denied for schema myschema
   LINE 1: SELECT * FROM myschema.t1;
   ```
   
   
3. 切换到管理员dbadmin。 
   ```
   gaussdb=> RESET SESSION AUTHORIZATION;
   RESET
   ```
   把myschema.t1的权限赋予用户user_1。
   ```
   gaussdb=> GRANT USAGE ON SCHEMA myschema TO user_1;
   GRANT
   ```
   
   
4. 切换到普通用户user_1。 
   ```
   gaussdb=> SET SESSION AUTHORIZATION user_1 PASSWORD '********';
   SET
   ```
   查询表myschema.t1。
   ```
   gaussdb=> SELECT * FROM myschema.t1;
    a | b
   ---+---
   (0 rows)
   ```
   
   
 
