本文介绍如何在 veDB MySQL 中使用 Hint 语法,以及相关的注意事项。
仅读写终端(自动读写分离)地址支持 Hint 语法,只读终端地址和主节点终端地址不支持 Hint 语法,即使在 SQL 语句中添加了 Hint 语法,也不会生效。连接终端详情信息请参见关于连接终端。
Hint 的路由优先级别最高,不受事务导致的连接绑定、一致性级别和事务拆分等功能的约束,使用前请进行评估是否可用于业务。
MySQL 命令行默认会过滤 SQL 语句中的注释,因此使用 MySQL 命令行执行 Hint 语句时,需要在连接数据库时加上 -c
选项,例如 mysql -h<连接地址> -P<端口> -u<用户名> -p -c
,否则会因 Hint 被过滤导致 Hint 失效,详情请参见 MySQL官方文档。
Hint 语句里不要有改变环境变量的语句,例如 /*FORCE_SLAVE*/ set names utf8;
等,这类语句可能导致后续的业务出错。也不要通过 Hint 设置用户变量,因为 Hint 指定后,只会对指定的节点设置变量,其它节点不会设置。如果使用不当,会导致同一前端连接的不同后端节点连接变量不一致。
veDB MySQL 支持以下三种 Hint:
在 SQL 语句中加上 /*FORCE_MASTER*/
强制指定 SQL 在主节点执行。
例如,select * from test;
正常情况下会被路由至只读节点,若在该语句中添加 Hint 语法,改为 /*FORCE_MASTER*/ select * from test
,则该语句会被强制路由至主节点。
在 SQL 语句中加上 /*FORCE_SLAVE*/
强制指定 SQL 在只读节点执行。
通过 /*FORCE_SLAVE*/
指定时,若该读写终端下存在多个只读节点,则会按照负载均衡策略发送 SQL 至其中一个只读节点上执行。
在 SQL 语句中加上 /*force_node=<节点ID>*/
强制指定 SQL 在某节点执行。
例如,/*force_node=vedbm-255rdo****-0*/ show processlist
,该 show processlist
命令只在 vedbm-255rdo****-0
节点上执行。如果该节点发生故障或指定的节点不存在,则返回报错 force hint server node is not found, please check
。
说明
Hint 语句不区分大小写,仅支持在 SQL 语句的句首使用 Hint。
在一条 SQL 语句中同时使用若干个 Hint,则仅生效最后一个 Hint。例如 /*FORCE_MASTER*//*FORCE_SLAVE*//*force_node=vedbm-255rdo****-0*/
,则生效 /*force_node=vedbm-255rdo****-0*/
。
通过 /*FORCE_SLAVE*/
或者 /*force_node=<节点ID>*/
强制指定只读节点执行写操作或 DDL 操作,例如 insert、update、alter table 等,则会返回报错 The MySQL server is running with the --replica-mode option so it cannot execute this statement
。
如果使用了 Hint 指定节点执行 PREPARE ,则 EXECUTE 也只能在对应的节点上执行。
MySQL [test]> /*FORCE_MASTER*/ PREPARE selecttest from 'select * from test where id=?'; Query OK, 0 rows affected (0.00 sec) Statement prepared MySQL [test]> set @a=555; Query OK, 0 rows affected (0.01 sec) # 指定在主节点执行命令或不指定节点,成功。 MySQL [test]> execute selecttest using @a; +------+------+ | id | code | +------+------+ | 555 | 05 | +------+------+ 1 row in set (0.01 sec) MySQL [test]> /*FORCE_MASTER*/ execute selecttest using @a; +------+------+ | id | code | +------+------+ | 555 | 05 | +------+------+ 1 row in set (0.00 sec) # 指定在只读节点执行命令,失败。 MySQL [test]> /* force_node=vedbm-apdm3ztf****-2 */ execute selecttest using @a; ERROR 1243 (HY000): Unknown prepared statement handler (selecttest) given to EXECUTE
通过 Hint 指定 set 在具体的节点上执行,则也只能在对应的节点上使用该变量。
MySQL [test]> /* force_node=vedbm-apdm3ztf****-1 */ set @a=111; Query OK, 0 rows affected (0.01 sec) MySQL [test]> /* force_node=vedbm-apdm3ztf****-1 */ select @a; +------+ | @a | +------+ | 111 | +------+ 1 row in set (0.00 sec) MySQL [test]> /*FORCE_MASTER*/ select @a; +------+ | @a | +------+ | NULL | +------+ 1 row in set (0.00 sec)
事务中 Hint 的优先级最高。
MySQL [test]> begin; Query OK, 0 rows affected (0.01 sec) MySQL [test]> INSERT INTO `test` VALUES ('222', '02'); Query OK, 1 row affected (0.01 sec) MySQL [test]> /*FORCE_SLAVE*/ select * from test; +------+------+ | id | code | +------+------+ | 111 | 01 | +------+------+ 1 row in set (0.01 sec) MySQL [test]> /*FORCE_MASTER*/ select * from test; +------+------+ | id | code | +------+------+ | 111 | 01 | | 222 | 02 | +------+------+ 2 rows in set (0.01 sec) MySQL [test]> INSERT INTO `test` VALUES ('333', '03'); Query OK, 1 row affected (0.01 sec) MySQL [test]> /*FORCE_MASTER*/ select * from test; +------+------+ | id | code | +------+------+ | 111 | 01 | | 222 | 02 | | 333 | 03 | +------+------+ 3 rows in set (0.01 sec) MySQL [test]> /*FORCE_SLAVE*/ select * from test; +------+------+ | id | code | +------+------+ | 111 | 01 | +------+------+ 1 row in set (0.00 sec) MySQL [test]> commit; Query OK, 0 rows affected (0.01 sec) MySQL [test]> /*FORCE_SLAVE*/ select * from test; +------+------+ | id | code | +------+------+ | 111 | 01 | | 222 | 02 | | 333 | 03 | +------+------+ 3 rows in set (0.01 sec)