表级副本的使用 
============================

本节主要介绍常用的一些表级副本变更操作。

租户级副本变更操作，请参见 [Locality 管理](../../../6.administrator-guide/5.data-distribution-and-link-management/3.locality-management/1.locality-management-overview.md) 章节。

表级副本主要通过建表时指定 Locality 属性或者 `ALTER TABLE` 语句指定 Locality 属性，示例语句如下所示：

```sql
CREATE TABLE table_name (...) locality='XXX,XXX,XXX';
ALTER TABLE table_name SET locality='XXX,XXX,XXX';
```



表级 Locality 操作范围 
-------------------------

默认表级 Locality 为空的表，通过变更租户 Locality 可批量调整租户下所有表的副本分布。Locality 不为空的表，可通过表级 Locality 变更来调整目标表的副本分布，即表级 Locality 的变更对象为表 Locality 不为空的表。

操作方式和变更进度查询 
--------------------

表级 Locality 的操作方式与租户级 Locality 相同，仅支持每次一个 Zone 上的 Locality 变更。并且变更后的表 Locality 仍然要满足与当前租户 Locality 的匹配限制。表级 Locality 的变更流程也与租户级 Locality 相同，但变更对象仅限于对单个目标表。变更执行后，可登录系统租户运行下述 SQL 语句以查询变更进度：

```sql
obclient> SELECt gmt_create, gmt_modified, tenant_id, table_name, job_type, job_status FROM __all_rootservice_job WHERE job_type LIKE '%LOCALITY%' ORDER BY job_id DESC;
```


**说明**



租户级 Locality 变更也可使用上述语句进行查询，返回结果中的 `tenant id` 和 `table_name` 列中会显示变更对象的具体值。对于表级 Locality 的变更，返回结果中的 `tenant_id` 为 NULL。

操作注意事项 
---------------

* 对表级 Locality 非空的不同目标表，Locality 变更操作可以同时进行。

  

* 对表级 Locality 非空的表执行 Locality 变更后，在变更未完成时不允许该表所属的租户发生 Locality 变更，即此时通过 `ALTER TENANT` 语句发起的租户 Locality 变更会失败。

  

* 对表级 Locality 非空的表，如果需要在 Zone 或 Region 中调整 `readonly` 或 `memonly` 等 `non_paxos` 类型副本（即不参与投票的副本）的数量时，需要直接修改租户的 Locality 属性列来实现。增减 `non_paxos` 副本的任务会直接交由 RootService 的负载均衡线程完成。

  

* 对表级 Locality 为空的表，如果需要在 Zone 和 Region 内增加 `non_paxos` 类型副本时，可通过 `ALTER TABLE` 修改此表。例如，`tenant Locality=F@z1,F@z2,F@z3` 中有一个 Locality 为空的表，通过 `ALTER TABLE` 修改为 `Locality=F@z1,F@z2,R@z3` 后该表的 Locality 不再为空。同样增减 `non_paxos` 副本的任务也是直接交由 RootService 的负载均衡线程完成。

  

* 不支持将 Locality 非空的表修改为空。

  

* sys 租户系统表的 Locality 必须与 sys 租户的 Locality 保持一致，即系统表的 Locality 始终为空，不支持修改系统表中表级 Locality 的修改。

  

* 在为整个租户的所有表增加、减少或修改 Locality 时，需要执行如下两步操作：

  1. 对租户 Locality 做变更。

     
  
  2. 对租户下所有不为空的表 Locality 做变更。

     在完成第一步租户 Locality 的变更后必须人工进行第二步表 Locality 的变更，如果越过第二步进行下一轮的租户 Locality 变更，将产生不可预知的错误。
     
  

  




示例 
-----------

假设集群在杭州有三个机房分别为 `hz1@Hangzhou`、`hz2@Hangzhou` 和 `hz3@Hangzhou`。且租户的默认三个全功能 Locality 分别设定为 `F@hz1`、`F@hz2` 和 `F@hz3`。

当需要定义一个表，且要求其只读副本部署在集群中所有 OBServer 节点上时，可以通过以下 SQL 语句进行创建：

```sql
CREATE TABLE table_name (...) locality = 'F@hz1, F@hz2, F@hz3, R{all_server}@hz1, R{all_server}@hz2, R{all_server}@hz3';
```



也可通过以下的 `ALTER TABLE` 语句进行修改：

```sql
ALTER TABLE table_name set locality = 'F@hz1, F@hz2, F@hz3, R{all_server}@hz1, R{all_server}@hz2, R{all_server}@hz3';
```



执行后等待 `__all_rootservice_job` 表中对应任务记录的状态变为 `SUCCESS`，即表示创建或修改完成。
**注意**



表级 Locality 的变更与租户级 Locality 变更具有如下制约关系：

* 在旧的一轮租户级 Locality 没有完成变更时，新一轮的租户级 Locality 变更不允许被执行。

  

* 当租户下 Locality 不为空的表的变更没有完成时，租户级 Locality 变更不允许执行。

  

* 当租户在目标 Zone 的 Locality 变更没有发起时，Locality 不为空的表在目标 Zone 的 Locality 变更不允许执行。

  




综上所述，租户级 Locality 变更不允许同时发起多轮变更，租户和表的 Locality 变更前需要先完成未完成的变更。
