版本日期:2024.03(最新版本以腾讯云官网产品文档为准,本链接为2024年3月版)
版权声明
本文档著作权归腾讯云计算(北京)有限责任公司(以下简称“腾讯云”)单独所有,未经腾讯云事先书面许可,任何主体不得以任何方式或理由使用本文档,包括但不限于复制、修改、传播、公开、剽窃全部或部分本文档内容。
本文档及其所含内容均属腾讯云内部资料,并且仅供腾讯云指定的主体查看。如果您非经腾讯云授权而获得本文档的全部或部分内容,敬请予以删除,切勿以复制、披露、传播等任何方式使用本文档或其任何内容,亦请切勿依本文档或其任何内容而采取任何行动。
免责声明
本文档旨在向客户介绍本文档撰写时,腾讯云相关产品、服务的当时的整体概况,部分产品或服务在后续可能因技术调整或项目设计等任何原因,导致其服务内容、标准等有所调整。因此,本文档仅供参考,腾讯云不对其准确性、适用性或完整性等做任何保证。您所购买、使用的腾讯云产品、服务的种类、内容、服务标准等,应以您和腾讯云之间签署的合同约定为准,除非双方另有约定,否则,腾讯云对本文档内容不做任何明示或默示的承诺或保证。
连接数据库
客户端连接
TDSQL MySQL版 提供和 MySQL 兼容的连接方式,用户可通过 IP 地址、端口号以及用户名、密码连接 TDSQL MySQL版:
mysql -hxxx.xxx.xxx.xxx -Pxxxx -uxxx -pxxx -c
TDSQL MySQL版 不支持4.0以下的版本以及压缩协议,建议在使用客户端的时候增加-c选项,以便于使用某些高级功能。
PHP MySQLli 连接
PHP 需要开启 MySQLli 扩展连接数据库,具体 demo 如下:
header("Content-Type:text/html;charset=utf-8");
$host="10.10.10.10"; //实例的 proxy_host_ip
$user="test"; //实例用户
$pwd="test"; //实例用户密码
$db="aaa"; //数据库名
$port="15002"; //proxy_host 端口号
$sqltool=new MySQLli($host,$user,$pwd,$db,$port);
//其他必要代码
$sqltool->close();
echo "ok"."\n";
JDBC 连接
您也可以使用 JDBC 连接 TDSQL MySQL版,例如:
private final String USERNAME = "test";
private final String PASSWORD = "123456";
private final String DRIVER = "com.mysql.jdbc.Driver";
private final String URL = "jdbc:mysql://10.10.10.10:3306?userunicode=true&characterEncoding=utf8mb4";
private Connection connection;
private PreparedStatement pstmt;
private ResultSet resultSet;
其他连接方式
您也可以选择其他兼容 MySQL 的连接方式,例如 navicat、odbc 等。
JOIN 和子查询
对于分布式实例,数据水平拆分在各个节点,为提高性能,建议优先优化表结构和 SQL,尽量使用不跨节点的方式。
推荐方式
多个分表,带有分表键相等的条件
MySQL > select * from test1 join test2 where test1.a=test2.a;
+---+------+---------+---+------+---------------+
| a | b | c | a | d | e |
+---+------+---------+---+------+---------------+
| 1 | 2 | record1 | 1 | 3 | test2_record1 |
| 2 | 3 | record2 | 2 | 3 | test2_record2 |
+---+------+---------+---+------+---------------+
2 rows in set (0.00 sec)
MySQL > select * from test1 left join test2 on test1.a<test2.a where test1.a=1;
+---+------+---------+------+------+---------------+
| a | b | c | a | d | e |
+---+------+---------+------+------+---------------+
| 1 | 2 | record1 | 2 | 3 | test2_record2 |
+---+------+---------+------+------+---------------+
1 row in set (0.00 sec)
MySQL> select * from test1 where test1.a in (select a from test2);
+---+------+---------+
| a | b | c |
+---+------+---------+
| 1 | 2 | record1 |
| 2 | 3 | record2 |
+---+------+---------+
2 rows in set (0.00 sec)
MySQL> select a, count(1) from test1 where exists (select * from test2 where test2.a=test1.a) group by a;
+---+----------+
| a | count(1) |
+---+----------+
| 1 | 1 |
| 2 | 1 |
+---+----------+
2 rows in set (0.00 sec)
MySQL> select distinct count(1) from test1 where exists (select * from test2 where test2.a=test1.a) group by a;
+----------+
| count(1) |
+----------+
| 1 |
+----------+
1 row in set (0.00 sec)
MySQL> select count(distinct a) from test1 where exists (select * from test2 where test2.a=test1.a);
+-------------------+
| count(distinct a) |
+-------------------+
| 2 |
+-------------------+
1 row in set (0.00 sec)
均为单表
mysql> create table noshard_table ( a int, b int key);
Query OK, 0 rows affected (0.02 sec)
mysql> create table noshard_table_2 ( a int, b int key);
Query OK, 0 rows affected (0.00 sec)
mysql> select * from noshard_table,noshard_table_2;
Empty set (0.00 sec)
mysql> insert into noshard_table (a,b) values(1,2),(3,4);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> insert into noshard_table_2 (a,b) values(10,20),(30,40);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from noshard_table,noshard_table_2;
+------+---+------+----+
| a | b | a | b |
+------+---+------+----+
| 1 | 2 | 10 | 20 |
| 3 | 4 | 10 | 20 |
| 1 | 2 | 30 | 40 |
| 3 | 4 | 30 | 40 |
+------+---+------+----+
4 rows in set (0.00 sec)
广播表
MySQL> create table global_test(a int key, b int)shardkey=noshardkey_allset;
Query OK, 0 rows affected (0.00 sec)
MySQL> insert into global_test(a, b) values(1,1),(2,2);
Query OK, 2 rows affected (0.00 sec)
MySQL> select * from test1, global_test;
+---+------+---------+---+------+
| a | b | c | a | b |
+---+------+---------+---+------+
| 1 | 2 | record1 | 1 | 1 |
| 2 | 3 | record2 | 1 | 1 |
| 1 | 2 | record1 | 2 | 2 |
| 2 | 3 | record2 | 2 | 2 |
+---+------+---------+---+------+
4 rows in set (0.00 sec)
子查询带有 shardkey 的 derived table
mysql> select a from (select * from test1 where a=1) as t;
+---+
| a |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
子查询时不指定 shardkey,也可查询结果。
复杂 SQL
对于不能满足推荐方式的 SQL,由于需要做跨节点的数据交互,所以性能会差一些。 包括:
- 包含子查询的查询。
- 多表的 join 查询,且参与查询的各表的分区字段(shardkey)不相等,或者同时涉及不同类型的表,例如单表和分表。
对于这类复杂查询,通过条件下推,将真正参与查询的数据从后端数据库中抽取出来,存放在本地的临时表中,然后对临时表中的数据进行计算。
因此用户需要明确指定参与查询的表的条件,避免因为抽取大量数据而性能受损。
mysql> create table test1 ( a int key, b int, c char(20) ) shardkey=a;
Query OK, 0 rows affected (1.56 sec)
mysql> create table test2 ( a int key, d int, e char(20) ) shardkey=a;
Query OK, 0 rows affected (1.46 sec)
mysql> insert into test1 (a,b,c) values(1,2,"record1"),(2,3,"record2");
Query OK, 2 rows affected (0.02 sec)
mysql> insert into test2 (a,d,e) values(1,3,"test2_record1"),(2,3,"test2_record2");
Query OK, 2 rows affected (0.02 sec)
mysql> select * from test1 join test2 on test1.b=test2.d;
+---+------+---------+---+------+---------------+
| a | b | c | a | d | e |
+---+------+---------+---+------+---------------+
| 2 | 3 | record2 | 1 | 3 | test2_record1 |
| 2 | 3 | record2 | 2 | 3 | test2_record2 |
+---+------+---------+---+------+---------------+
2 rows in set (0.00 sec)
MySQL> select * from test1 where exists (select * from test2 where test2.a=test1.b);
+---+------+---------+
| a | b | c |
+---+------+---------+
| 1 | 2 | record1 |
+---+------+---------+
1 row in set (0.00 sec)
分布式实例还支持丰富的复杂 update/delete/insert 操作。
需要注意的是,这类查询是在与之对应的 select 基础上实现的,因此也需要将数据加载至网关临时表,建议用户尽量在查询中指定明确的查询条件,避免大量数据的加载带来性能损耗。 另外,网关在加载数据时默认不会对加载的数据进行上锁,这与官方的 MySQL 行为存在略微的差异;如需加锁可以通过修改 proxy 配置来实现。
MySQL [th]> update test1 set test1.c="record" where exists(select 1 from test2 where test1.b=test2.d);
Query OK, 1 row affected (0.00 sec)
MySQL [th]> update test1, test2 set test1.b=2 where test1.b=test2.d;
Query OK, 1 row affected (0.00 sec)
MySQL [th]> insert into test1 select cast(rand()*1024 as unsigned), d, e from test2;
Query OK, 2 rows affected (0.00 sec)
MySQL [th]> delete from test1 where b in (select b from test2);
Query OK, 6 rows affected (0.00 sec)
MySQL [th]> delete from test2.* using test1 right join test2 on test1.a=test2.a where test1.a is null;
Query OK, 2 rows affected (0.00 sec)
Sequence
关键字 Sequence 语法和 MariaDB/Oracle 兼容,但是保证分布式全局递增且唯一,具体使用如下:
- TDSQL_INCREMENT BY 设置序列步长,正数表示升序序列,负数表示降序序列。设置值必须在序列最大值与最小值之间,缺省则默认1。
- START WITH 设置序列起始值,缺省则默认序列最小值。
- TDSQL_MAXVALUE 和 TDSQL_NOMAXVALUE 设置序列最大值,TDSQL_MAXVALUE 缺省或者设置TDSQL_NOMAXVALUE 时,递增序列最大值为9223372036854775807,递减序列最大值为-1。
- TDSQL_MINVALUE 和 TDSQL_NOMINVALUE 设置序列最小 TDSQL_MINVALUE 缺省或者设置TDSQL_NOMINVALUE 时,递增序列最小值为1,递减序列最小值为-9223372036854775808。
- TDSQL_CYCLE 和 TDSQL_NOCYCLE 设置序列是否循环,缺省默认不循环。
- TDSQL_CACHE 和 TDSQL_NOCACHE 设置缓存序列数量,缺省默认缓存20。
- TDSQL_ORDER 和 TDSQL_NOORDER。设置序列对于并发请求保证完全有序。TDSQL 目前仅支持无序。
- 在 TDSQL MySQL 版 分布式数据库当中使用 Sequence 时,须在该关键字前面加 tdsql_ 前缀,且要求 proxy 版本最低为1.19.5-M-V2.0R745D005;可通过数据库管理语句 /*Proxy*/show status 查询 proxy 版本,若 proxy 版本较老可以 提交工单 进行升级。
- 目前 Sequence 为保证分布式全局数值唯一,导致性能较差,主要适用于并发不高的场景。
创建序列需要 CREATE SEQUENCE 系统权限。序列的创建语法如下:
CREATE TDSQL_SEQUENCE 序列名
[START WITH n]
[{TDSQL_MINVALUE | TDSQL_MAXVALUE} n | TDSQL_NOMINVALUE | TDSQL_NOMAXVALUE]
[TDSQL_INCREMENT BY n]
[{TDSQL_CYCLE|TDSQL_NOCYCLE}]
[{TDSQL_CACHE|TDSQL_NOCACHE} n]
创建 Sequence
create tdsql_sequence test.s1 start with 12 tdsql_minvalue 10 maxvalue 50000 tdsql_increment by 5 tdsql_nocycle
create tdsql_sequence test.s2 start with 12 tdsql_minvalue 10 maxvalue 50000 tdsql_increment by 1 tdsql_cycle
- 以上 SQL 语句包含开始值、最小值、最大值、步长、缓存大小及是否回绕6个参数。
- 参数默认值,开始值(1)、最小值(1)、最大值(LONGLONG_MAX-1)、步长(1)、是否回绕(0)。
删除 Sequence
drop tdsql_sequence test.s1
查询 Sequence
show create tdsql_sequence test.s1
使用 Sequence
使用 Sequence 获取下一个数值
select tdsql_nextval(test.s2)
select next value for test.s2
mysql> select tdsql_nextval(test.s1);
+----+
| 12 |
+----+
| 12 |
+----+
1 row in set (0.18 sec)
mysql> select tdsql_nextval(test.s2);
+----+
| 12 |
+----+
| 12 |
+----+
1 row in set (0.13 sec)
mysql> select tdsql_nextval(test.s1);
+----+
| 17 |
+----+
| 17 |
+----+
1 row in set (0.01 sec)
mysql> select tdsql_nextval(test.s2);
+----+
| 13 |
+----+
| 13 |
+----+
1 row in set (0.00 sec)
mysql> select next value for test.s1;
+----+
| 22 |
+----+
| 22 |
+----+
1 row in set (0.01 sec)
nextval 可以用在 insert 等地方
mysql> select * from test.t1;
+----+------+
| a | b |
+----+------+
| 11 | 2 |
+----+------+
1 row in set (0.00 sec)
mysql> insert into test.t1(a,b) values(tdsql_nextval(test.s2),3);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test.t1;
+----+------+
| a | b |
+----+------+
| 11 | 2 |
| 14 | 3 |
+----+------+
2 rows in set (0.00 sec)
如需获取上一次的值以连接相关数据:如果之前没有用 nextval 命令获取过数据,数值将返回为0。
select tdsql_lastval(test.s1)
select tdsql_previous value for test.s1;
mysql> select tdsql_lastval(test.s1);
+----+
| 22 |
+----+
| 22 |
+----+
1 row in set (0.00 sec)
mysql> select tdsql_previous value for test.s1;
+----+
| 22 |
+----+
| 22 |
+----+
1 row in set (0.00 sec)
设置下一个序列数值,只能比当前数值大,否则将返回数值为0。
select tdsql_setval(test.s2,1000,bool use) // use 默认为1,表示1000这个值用过了,下一次不包含1000,如果为0,则下一个从1000开始。
设置下一个序列数值时,如果比当前数值小,则设置不生效。
mysql> select tdsql_nextval(test.s2);
+----+
| 15 |
+----+
| 15 |
+----+
1 row in set (0.01 sec)
mysql> select tdsql_setval(test.s2,10);
+---+
| 0 |
+---+
| 0 |
+---+
1 row in set (0.03 sec)
mysql> select tdsql_nextval(test.s2);
+----+
| 16 |
+----+
| 16 |
+----+
如果比当前数值大,成功返回当前设置的值。
mysql> select tdsql_setval(test.s2,20);
+----+
| 20 |
+----+
| 20 |
+----+
1 row in set (0.02 sec)
mysql> select tdsql_nextval(test.s2);
+----+
| 21 |
+----+
| 21 |
+----+
1 row in set (0.01 sec)
强制设置下一个序列数值,允许设置比当前数值小的值。
select tdsql_resetval(test.s2,1000)
如果强制设置成功,返回当前设置的值,下一个序列数值从该值开始。
mysql> select tdsql_resetval(test.s2,14);
+----+
| 14 |
+----+
| 14 |
+----+
1 row in set (0.00 sec)
mysql> select tdsql_nextval(test.s2);
+----+
| 14 |
+----+
| 14 |
+----+
1 row in set (0.01 sec)
需要注意,Sequence 的部分关键字以 TDSQL_ 前缀开始:
若已打开 oldstyle 配置项,proxy 将兼容标准 Sequence 关键字,即关键字前可不添加TDSQL_ 前缀。
TDSQL_CYCLE
TDSQL_INCREMENT
TDSQL_LASTVAL
TDSQL_MINVALUE
TDSQL_NEXTVAL
TDSQL_NOCACHE
TDSQL_NOCYCLE
TDSQL_NOMAXVALUE
TDSQL_NOMINVALUE
TDSQL_PREVIOUS
TDSQL_RESTART
TDSQL_REUSE
TDSQL_SEQUENCE
TDSQL_SETVAL




