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,否则无法创建表。 场景:存在多个唯一索引时报错。

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;

此时有一个唯一索引u_2不包含 shardkey,无法创建表,会报如下错误:

ERROR 1105 (HY000): A UNIQUE INDEX must include all columns in the table's partitioning function

因为主键索引或者 unique key 索引意味着需要全局唯一,而要实现全局唯一索引,则必须包含 shardkey 字段。 除上面的限制外,shardkey 字段还有如下要求: * shardkey 字段的类型必须是 int、bigint、smallint、char、varchar。 * shardkey 字段类型为 char、varchar 时需定义字段长度。 * shardkey 字段的值不能有中文,proxy 不会转换字符集,因此不同字符集可能会路由到不同的分区。 * 不能 update shardkey 字段的值。 * shardkey=a 放在 SQL 的最后面。 * 访问数据尽量都带上 shardkey 字段,非强制要求,但是不带 shardkey 的 SQL 会路由到所有节点,消耗较多资源。 另外,创建表的时候,可以使用自增序列作为某一列的默认值,并把这一列设置为主键。

    CREATE TABLE test2(column1 INT,column2 INT,column3 INT AUTO_INCREMENT,PRIMARY KEY(column3)) AUTO_INNCREMENT=5 shardkey=column3;

插入数据时,设置为自增序列的列插入Null值。

  INSERT INTO test2(column1,column2,column3) VALUES(0,0,NULL);

建广播表

支持建小表(广播表),此时该表在所有 set 中都是全量数据,主要方便于跨 set 的 join 操作,同时通过分布式事务保证修改操作的原子性,使得所有 set 的数据完全一致。

mysql> create table global_table ( a int, b int key) shardkey=noshardkey_allset;
Query OK, 0 rows affected (0.06 sec)

建单表

支持建立普通的表,语法和 MySQL 完全一致,此时该表的数据全量存在第一个 set 中,所有该类型的表都放在第一个 set 中:

    mysql> create table noshard_table ( a int, b int key);
    Query OK, 0 rows affected (0.02 sec)

二级分区

TDSQL MySQL版 目前支持 Range 和 List 两种格式的二级分区,具体建表语法和 MySQL 分区语法类似。

二级分区语法

一级 Hash,二级 List 分区示例如下:

MySQL [test]> CREATE TABLE customers_1 (
  first_name VARCHAR(25) key,
  last_name VARCHAR(25),
  street_1 VARCHAR(30),
  street_2 VARCHAR(30),
  city VARCHAR(15),
  renewal DATE
) shardkey=first_name

PARTITION BY LIST (city) (
  PARTITION pRegion_1 VALUES IN('Beijing', 'Tianjin', 'Shanghai'),
  PARTITION pRegion_2 VALUES IN('Chongqing', 'Wulumuqi', 'Dalian'),
  PARTITION pRegion_3 VALUES IN('Suzhou', 'Hangzhou', 'Xiamen'),
  PARTITION pRegion_4 VALUES IN('Shenzhen', 'Guangzhou', 'Chengdu')
);

一级 Range,二级 List 创建语法如下:

MySQL [test]> CREATE TABLE tb_sub_r_l (
   id int(11) NOT NULL,
   order_id bigint NOT NULL,
   PRIMARY KEY (id,order_id)) 
   PARTITION BY list(order_id)
   (PARTITION p0 VALUES in (2121122),
   PARTITION p1 VALUES in (38937383))
   TDSQL_DISTRIBUTED BY RANGE(id) (s1 values less than (100),s2 values less than (1000));
Query OK, 0 rows affected, 1 warning (0.35 sec)
  • Range 支持类型
  • DATE,DATETIME,TIMESTAMP。
  • 支持 year、month、day 函数,函数为空和 day 函数一样。
  • TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT。
  • 支持 year、month、day 函数,此时传入的值转换为年月日,然后和分表信息进行对比。

  • List 支持类型

  • DATE、DATETIME、TIMESTAMP。
  • 支持年月日函数
  • TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT、VARCHAR。

*警告: - 建议不要使用 TIMESTAMP 类型作为分区键,因为 TIMESTAMP 受到时区的影响,同时只能使用到2038年。 - 如果分区键是 char 或者 varchar 类型,建议长度不超255。

使用场景和方法建议

建议业务尽量都使用一级分区表。 * 使用前根据业务长期场景合理设计表结构,二级分区适用于表结构创建后长期都不需要 DDL 变更、需要定期进行分区数据清理和裁剪的场景,如日志流水表。 * 合理设计二级分区的粒度,二级分区的粒度建议不要划分得太细,避免产生过多的二级子表。如流水表按月进行二级分区,而不是按天/小时进行分区,避免文件系统上数据文件个数过多。 * 在对二级分区表进行 SQL 查询时,查询条件需要尽量带上一级分区和二级分区的键值,避免执行查询时需要打开很多的数据文件进行搜索。 * 在对二级分区表进行 join 查询时,如果查询条件未能带上一级分区和二级分区的键值,操作性能效率较低,建议不要使用。 * 表的主键或唯一索引需要包含分区键,否则无法保证数据唯一性。

透传 SQL

TDSQL MySQL版 实例会对 SQL 进行语法解析,有一定的限制,如果用户想在某个节点(set)中执行 MySQL 支持,但分布式实例不支持的 SQL 时,可以使用透传 SQL 的功能。

说明 * 透传 SQL 时,proxy 不会解析 SQL,如果是往两个 set 进行透传写操作,不会使用分布式事务,特殊情况下会发生不一致问题,因此对于写操作建议一次透传一个 set。 * 为保证透传语法生效,连接 MySQL 时请使用 -c 参数。

MySQL [test]> repair table test.t1;
ERROR 664 (HY000): Proxy ERROR:SQL is too complex, only applicable to noshard table: Shard table do not support repair
MySQL [test]> /*sets:allsets*/repair table test.t1;
+---------+--------+----------+----------+------------------+
| Table   | Op     | Msg_type | Msg_text | info             |
+---------+--------+----------+----------+------------------+
| test.t1 | repair | status   | OK       | set_1544429866_3 |
| test.t1 | repair | status   | OK       | set_1544429718_1 |
+---------+--------+----------+----------+------------------+
2 rows in set (0.01 sec)

具体语法: * sets:set_1,set_2:代表指定某几个 set,set 名字可以通过/proxy/show status查询。 * sets:allsets:代表指定全部 set。 * shardkey:10:代表支持透传 SQL 到 shardkey 对应值上的 set。 * shardkey_hash:10:透传到负责 hash 值为10的 set,如果为0,则发送到第一个 set 上。