首页 » linux » 正文

创建分表

通过分区字段(shardkey)把一个大表水平拆分到多个数据库,下面给大家介绍下分表的方法:

如何选择分区字段

一旦定好分区字段,就不能轻易修改分区字段,因此开发人员需要提前评估。选择分区字段的时候主要考虑两个维度:

  • 通过该字段能否对数据进行均衡的存储和访问
  • 多个相关联的表能否使用同一个字段。(相同分区字段数据会存储在同一个物理分片中,大多数的业务逻辑需要进行join时,可无需走分布式事务逻辑而直接在单节点内执行,效率大大提示)

举个例子,如果业务有两张表,一个用于记录用户的基本信息,一个用于用户的订单信息,此时如果选取用户ID作为shardkey,则理论数据分布和访问都会比较均衡,同时单个用户对应的基本信息和订单信息都会在一个后端数据库中,方便后续的join等操作。

shardkey选择的限制

普通的分表创建时在最后面指定shardkey的值,该值为表中的一个字段名字,会用于后续sql的路由选择:

shardkey字段有限定要求如下:

1.如存在主键或者唯一索引,则shardkey字段必须是主键以及所有唯一索引的一部分
2.shardkey字段的类型必须是int,bigint,smallint/char/varchar
3.shardkey字段的值尽量使用ascii码,网关不会转换字符集,所以不同字符集可能会路由到不同的分区(且尽量不要有中文)
4.不要update shardkey字段的值,如必须则先delete,再insert5.`shardkey=` 放在create语句的最后面,如下示例
6.访问数据尽量都能带上shardkey字段


创建一张分表

    mysql> create table test.right ( a int not null,b int not null, c char(20) not null,primary key(a,b) ,unique key(a,c)) shardkey=a;
    Query OK, 0 rows affected (0.12 sec)

shardkey'是系统标记分片字段的关键字,不可占用。
shardkey=noshardkey_allset定义该表为广播表的关键字,广播表表示该表不分表,但会在每个物理分片中都存储一份。

常见DML操作

使用分表时,对DML有一定的要求,具体如下(下面的例子中a为shardkey):

SELECT最好带上shardkey

select最好带上shardkey字段,由于分布式路由默认采用hash方式。

  • 若是=或者in,路由将自动跳转到对应分片,此时效率最高。
  • 若无=或者in,分布式系统会自动全表扫描,然后在网关进行结果集聚合,此时效率较低:

例如:下面两条sql根据shardkey的值直接可以发送到对应的数据库,通常5ms内可以处理完成。

    mysql> select a,b,c from test.test1 where a=2 order by b;
    mysql> select a,b,c from test.test1 where a in (2) order by b;

例如:如下的sql都会发到所有的后端数据库,然后需要对数据进行额外的汇总排序,通常要5~20ms才能处理完成。

    mysql> select a,b,c from test.test1 where a>2 order by b;
    mysql> select a,b,c from test.test1 where c=2 order by b;

insert/replace字段必须包含shardkey

insert/replace字段必须包含shardkey,否则路由不知道应该将数据插入到哪个物理分片,会拒绝执行该sql;

    mysql> insert into test.test1 (b,c) values(4,"record3");
    ERROR 1105 (07000): Proxy Warning - sql have no shardkey

    mysql> insert into test.test1 (a,c) values(4,"record3");
    Query OK, 1 row affected (0.01 sec)

使用广播表或单表时除外。

delete/update字段必须包含shardkey

delete/update时为了安全考虑,执行该类sql的时候必须带有where条件,系统拒绝执行该sql命令,where条件最好也和select一样带上shardkey:

    mysql> delete from test.test1;
    ERROR 1005 (07000): Proxy Warning - sql is not legal,tokenizer_gram went wrong
    mysql> delete from test.test1 where a=1;
    Query OK, 1 row affected (0.01 sec)

使用广播表或单表时除外。

修改shardkey字段值

同时update不能修改shardkey的字段的值,需要的话先insert再delete

    mysql> update test.test1 set a=10 where d=1;
    ERROR 7013 (HY000): Proxy ERROR:combine_sql_key return null,something went wrong
    mysql> update test.test1 set d=1 where a=1;
    Query OK, 0 rows affected (0.00 sec)

不能更换shardkey字段类型、修改字段名称、删除shardkey字段、或更换shardkey字段,除非您新建一个表。

常见问题:

表没有主键:

    mysql> create table test.e1 ( a int ,b int) shardkey=a;
    ERROR 1105 (HY000): This table type requires a primary key

主键或者唯一键没有包含shardkey:

    mysql> create table test.e2 ( a int not null,b int not null, c char(20) not null,primary key(a,b) ) shardkey=c;
    ERROR 1105 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

shardkey的拼写错误或者列名错误:

    mysql> create table test.e3 ( a int key,b int,c char(20)) shardkey1=d;
    ERROR 1911 (HY000): Unknown option 'shardkey1'
    mysql> create table test.e4 ( a int key,b int,c char(20)) shardkey=d;
    ERROR 7008 (HY000): Proxy ERROR:shardkey must be one of the column

发表评论