这是Tank的第18篇文章
1 关于分片键
分布式数据库通过将表的数据打散,按一定规则将数据分布在多个独立的主机上,常见的策略如HASH、RANGE、LIST等分布方式。不考虑中间件的解决方案,在原生分布式数据库产品中,表中主键字段为分片键(Sharding Key),或在业务字段外单独设定一个分片字段作为分片键,数据库提供服务的过程中,所有请求都离不开分片键的协调定位。2 唯一索引的方案
计算与存储的分布的设计,目的在提升系统的吞吐和容量,同时带来更高的可用性、更好的可扩展性。在传统集中数据库向分布式数据库迁移的过程中,如果应用系统在设计上多次使用到唯一约束或索引,问题来了:分布式数据库如何实现非主键列的唯一约束或唯一索引?a.尽量选取唯一索引字段作为Sharding Key来实现
b.在a方案不能满足的情况下,如单表多个唯一索引的情况,使用克隆方式存储数据,需考虑空间消耗
c.考虑通过应用改写的方式来实现唯一索引的使用需求
本段内容引用自知乎用户:朱翀
链接:
https://www.zhihu.com/question/346579248/answer/831432102
3 产品现状
在能够检索到的产品资料中,创建唯一索引时都是需要指定Sharding Key的。如TBase、TDSQL、Sequoiadb 3.2、OceanBase 2.2.50、TiDB 4.0、KingbaseES V8R3、GoldenDB 5.0、PolarDB-X,唯一索引的创建都需要包含Sharding Key。TBase
建议每个 table 都使用 shard key 作为主键或者唯一索引。
建议建表时一步到位,一起建立主键或者唯一索引。
非 shard key 不可以建立 primary key 或者 unique index。
postgres=# create unique index t_first_col_share_id_uidx on t_first_col_share using btree(id);CREATE INDEX
非 shard key 字段不能建立唯一索引
postgres=# create unique index t_first_col_share_nickname_uidx on t_first_col_share using btree(nickname);ERROR: Unique index of partitioned table must contain the hash/modulo distribution column.
TDSQL
分表创建时必须在最后面指定分表键(shardkey)的值,该值为表中的一个字段名字,会用于后续 SQL 的路由选择:mysql> create table test1 ( a int, b int, c char(20),primary key (a,b),unique key u_1(a,c) ) shardkey=a;Query OK, 0 rows affected (0.07 sec)
在分布式实例中,shardkey 对应后端数据库的分区字段,因此每一个唯一索引和主键都必须要包含这个 shardkey,否则无法创建表。存在多个唯一索引时报错。此时有一个唯一索引u_2不包含 shardkey,无法创建表,会报如下错误:
mysql> create table test1 ( a int,b int, c char(20),primary key (a,b),unique key u_1(a,c),unique key u_2(b,c) ) shardkey=a;;ERROR 1105 (HY000): A UNIQUE INDEX must include all columns in the table's partitioning function
主键索引或者 unique key 索引意味着需要全局唯一,而要实现全局唯一索引,则必须包含 shardkey 字段。
Sequoiadb 3.2
在分区集合中,所有的唯一索引必须包含集合分区键中所指定的全部字段。分区集合中,“$id”索引仅保证单节点内记录的唯一性。如果用户希望指定全局唯一的字段,需要额外创建唯一索引,且该索引必须包含集合分区键中所指定的全部字段。OceanBase 2.2.50
由于 OceanBase 的表是索引组织表(IOT),为了保证主键的含义,即给定主键的查询能很快定位到所在的分区。所以分区键必须是主键的子集。如果表里还包含唯一索引,那么要求 Oracle 模式的 IOT 表和索引分区的分区键就必须是所有唯一索引列(包括主键列)交集的子集,对表不做要求。TiDB 4.0
分区表的每个唯一键,必须包含分区表达式中用到的所有列。这里所指的唯一也包含了主键,因为根据主键的定义,主键必须是唯一的。DDL 变更时,添加唯一索引也需要考虑到这个限制。比如创建了这样一个表:CREATE TABLE t_no_pk (c1 INT, c2 INT) PARTITION BY RANGE(c1) ( PARTITION p0 VALUES LESS THAN (10), PARTITION p1 VALUES LESS THAN (20), PARTITION p2 VALUES LESS THAN (30), PARTITION p3 VALUES LESS THAN (40) );Query OK, 0 rows affected (0.12 sec)
通过 ALTER TABLE 添加非唯一索引是可以的。但是添加唯一索引时,唯一索引里面必须包含 c1 列。
KingbaseES V8R3
KingbaseES会自动为定义了一个唯一约束或主键的表创建一个唯一索引。该索引包含组成主键或唯一约束的所有列(可能是一个多列索引),它也是用于强制这些约束的机制。GoldenDB 5.0
当表是多节点分布存储时,如果唯一索引字段包含了分发字段,唯一索引功能可以正常使用,否则会存在一个明显的限制:不同DB节点间数据没有唯一性约束。PolarDB-X
全局二级索引定义子句[UNIQUE] GLOBAL:定义全局二级索引,UNIQUE GLOBAL代表全局唯一索引。index_name:索引名,也是索引表的名称。index_type:索引表中分库分表键上局部索引的类型,支持范围请参见MySQL 文档。index_sharding_col_name,...:索引列,包含且仅包含索引表的全部分库分表键,详情请参见全局二级索引。global_secondary_index_option:PolarDB-X 1.0全局二级索引的扩展语法。COVERING (col_name,...):覆盖列,索引表中除索引列以外的其他列,默认包含主键和主表的分库分表键,详情请参见全局二级索引。drds_partition_options:索引表的分库分表子句,详情请参见分库分表子句和参数。index_option:索引表中分库分表键上局部索引的属性,详情请参见MySQL 文档。