# （高级）如何使用 OceanBase 复制表

## 复制表原理

复制表指的是一种特殊的表。
普通的表在生产环境，默认有三副本，其中一个主副本和两个备副本。备副本通过同步主副本的事务日志 `clog` 保持同步，同步协议是 Paxos 协议，主副本的事务日志只有在多数成员里确认落盘后，事务修改才会生效。
通常，默认情况下，读写都是在主副本上，备副本是不提供读写服务。应用如果开启会话或语句级别的弱一致性读后，备副本可能会提供只读服务。风险就是备副本的读会有些许延迟。
普通表可以变为复制表，然后主副本和所有备副本之间使用全同步协议，主副本的事务日志只有在所有副本成员里确认落盘后，事务修改才会生效。所以主副本跟所有备副本的数据理论上都是强一致的。

## 复制表场景

传统普通的表，主副本可能会成为读写瓶颈，业务可能会使用读写分离技术，将只读查询分离出去。运维将只读查询路由到备副本。这个风险是备副本理论上有一定延时。如果表是复制表，则备副本没有延迟问题。这是一种使用场景，前提是开启弱一致性读。

复制表最有用的场景是业务数据库做了水平拆分后，有部分业务表不适合拆分。前者的数据主副本有可能在所有机器上，后者的主副本只会在某台机器上。OceanBase 里一个事务的 SQL 都会跟随到事务开始时那条 SQL 的路由，如果某个 SQL 被路由到的节点不是该 SQL 访问的分区的主副本节点，这个 SQL 就是个远程 SQL 。如果这个分区所在的表是复制表，则这条 SQL 就会在本机执行，从而提升性能。

复制表使用的前提是表的修改频率不能太高，每个事务的平均延时会比普通的表的事务延时要大。

## 复制表语法

可以在创建表的时候就指定复制表属性 `DUPLICATE_SCOPE` 。这个属性有下面几个值：

+ `NONE` : 这个是默认值，表示是普通的表。
+ `CLUSTER` ：表的备副本分布在租户资源池所在的所有机器上。

示例：

```sql
mysql> create table t1(id bigint not null auto_increment , c1 varchar(50), c2 timestamp not null default current_timestamp) duplicate_scope='cluster' ;                                                   Query OK, 0 rows affected (0.12 sec)

```

也可以在表创建好后修改这个属性。

示例：

```sql
mysql> alter table t1 duplicate_scope = 'NONE';
Query OK, 0 rows affected (0.05 sec)

mysql> alter table t1 duplicate_scope = 'CLUSTER';
Query OK, 0 rows affected (0.04 sec)

```
