全部产品
分布式关系型数据库 DRDS

指定分库执行 SQL

更新时间:2017-08-17 14:15:58   分享:   

在使用 DRDS 的过程中,如果遇到某个 DRDS 不支持的 SQL 语句,可以通过 DRDS 提供的自定义 HINT,直接将 SQL 下发到一个或多个分库上去执行。此外如果需要单独查询某个分库或者已知分库的某个分表中的数据,也可以使用该自定义 HINT,直接将 SQL 语句下发到分库中执行。

语法

指定分库执行 SQL 自定义 HINT 有两种使用方式,即通过分片名指定 SQL 在分库上执行或者通过分库键值指定 SQL 在分库上执行。其中分片名是 DRDS 中分库的唯一标识,可以通过 SHOW NODE 控制指令得到。

通过分库名指定 SQL 在分库上执行

通过分库名指定 SQL 在分库上执行又分两种使用方式,分别是指定 SQL 在某个分库上执行和指定 SQL 在多个分库上执行。

  • 指定 SQL 在某个分库上执行:

    1. /!TDDL:NODE='node_name'*/

    node_name 为分片名,通过这个 DRDS 自定义 HINT,就可以将 SQL 下发到node_name对应的分库中执行。

  • 指定 SQL 在多个分库上执行:

    1. /!TDDL:NODE IN ('node_name'[,'node_name1','node_name2'])*/

    使用 in 关键字指定多个分片名,将 SQL 下发到多个分库上执行,括号内分片名之间使用逗号分隔。

注意:使用该自定义 HINT 时,DRDS 会将 SQL 直接下发到分库上执行,所以在 SQL 语句中,表名必须是该分库中已经存在的表名。

通过分库键值指定 SQL 在分库上执行

  1. /!TDDL:table_name.partition_key=value [and table_name1.partition_key=value1]*/

在这个 DRDS 自定义 HINT 中table_name为逻辑表名,该表是一张拆分表,partition_key是拆分键,value为指定的拆分键的值。在该自定义注释中,可以使用and关键字指定多个拆分表的拆分键。通过这个 DRDS 自定义 HINT,DRDS 会计算出 SQL 语句应该在哪些分库和分表上执行,进而将 SQL 语句下发到相应的分库。

注意:

  • DRDS 自定义 HINT 支持 /!TDDL:hint command*//*TDDL:hint command*/ 两种格式。

  • 如果使用 /*TDDL:hint command*/ 格式,在使用 MySQL 官方命令行客户端执行带有 DRDS 自定义 HINT 的 SQL 时,请在登录命令中加上 -c 参数。否则,由于 DRDS 自定义 HINT 是以 MySQL 注释 形式使用的,该客户端会将注释语句删除后再发送到服务端执行,导致 DRDS 自定义 HINT 失效。具体请查看 MySQL 官方客户端命令

示例

对于名为 drds_test 的 DRDS 数据库,SHOW NODE 的结果如下:

  1. mysql> SHOW NODE\G
  2. *************************** 1. row ******************
  3. ID: 0
  4. NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0000_RDS
  5. MASTER_READ_COUNT: 212
  6. SLAVE_READ_COUNT: 0
  7. MASTER_READ_PERCENT: 100%
  8. SLAVE_READ_PERCENT: 0%
  9. *************************** 2. row ******************
  10. ID: 1
  11. NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0001_RDS
  12. MASTER_READ_COUNT: 29
  13. SLAVE_READ_COUNT: 0
  14. MASTER_READ_PERCENT: 100%
  15. SLAVE_READ_PERCENT: 0%
  16. *************************** 3. row ******************
  17. ID: 2
  18. NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0002_RDS
  19. MASTER_READ_COUNT: 29
  20. SLAVE_READ_COUNT: 0
  21. MASTER_READ_PERCENT: 100%
  22. SLAVE_READ_PERCENT: 0%
  23. *************************** 4. row ******************
  24. ID: 3
  25. NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0003_RDS
  26. MASTER_READ_COUNT: 29
  27. SLAVE_READ_COUNT: 0
  28. MASTER_READ_PERCENT: 100%
  29. SLAVE_READ_PERCENT: 0%
  30. *************************** 5. row ******************
  31. ID: 4
  32. NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0004_RDS
  33. MASTER_READ_COUNT: 29
  34. SLAVE_READ_COUNT: 0
  35. MASTER_READ_PERCENT: 100%
  36. SLAVE_READ_PERCENT: 0%
  37. *************************** 6. row ******************
  38. ID: 5
  39. NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0005_RDS
  40. MASTER_READ_COUNT: 29
  41. SLAVE_READ_COUNT: 0
  42. MASTER_READ_PERCENT: 100%
  43. SLAVE_READ_PERCENT: 0%
  44. *************************** 7. row ******************
  45. ID: 6
  46. NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0006_RDS
  47. MASTER_READ_COUNT: 29
  48. SLAVE_READ_COUNT: 0
  49. MASTER_READ_PERCENT: 100%
  50. SLAVE_READ_PERCENT: 0%
  51. *************************** 8. row ******************
  52. ID: 7
  53. NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0007_RDS
  54. MASTER_READ_COUNT: 29
  55. SLAVE_READ_COUNT: 0
  56. MASTER_READ_PERCENT: 100%
  57. SLAVE_READ_PERCENT: 0%
  58. 8 rows in set (0.02 sec)

可以看到每个分库都有 NAME 这个属性,这就是分库的分片名。每个分片名都唯一对应一个分库名,比如DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0003_RDS这个分片名对应的分库名是drds_test_vtla_0003。得到了分片名,就可以使用 DRDS 的自定义 HINT 指定分库执行 SQL 语句了。

  • 指定 SQL 在第 0 个分库上执行:

    1. /!TDDL:NODE='DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0000_RDS'*/SELECT * FROM table_name;
  • 指定 SQL 在多个分库上执行:

    1. /!TDDL:NODE IN('DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0000_RDS','DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0006_RDS')*/SELECT * FROM table_name;

    这条 SQL 语句将在DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0000_RDSDRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0006_RDS这两个分片上执行。

  • 查看某个分库的执行计划:

    1. /!TDDL:NODE='DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0000_RDS'*/EXPLAIN SELECT * FROM table_name;

    这条 SQL 语句将会展示 SELECT 语句在分片 DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0000_RDS 中的执行计划。

  • 通过键值指定 SQL 在分库上执行:

    对于UPDATE语句,DRDS 不支持SET子句中的子查询,由于UPDATE语句在 DRDS 中必须指定拆分键,所以可以使用 DRDS 的自定义 HINT 将该语句直接下发到分库上执行。

    比如有两张逻辑表,分别是 t1 和 t2,它们都是分库分表,建表语句如下:

    1. CREATE TABLE `t1` (
    2. `id` bigint(20) NOT NULL,
    3. `name` varchar(20) NOT NULL,
    4. `val` varchar(20) DEFAULT NULL,
    5. PRIMARY KEY (`id`)
    6. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by hash(`id`) tbpartition by hash(`name`) tbpartitions 3
    7. CREATE TABLE `t2` (
    8. `id` bigint(20) NOT NULL,
    9. `name` varchar(20) NOT NULL,
    10. `val` varchar(20) DEFAULT NULL,
    11. PRIMARY KEY (`id`)
    12. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by hash(`id`) tbpartition by hash(`name`) tbpartitions 3

    需要执行的语句是:

    1. UPDATE t1 SET val=(SELECT val FROM t2 WHERE id=1) WHERE id=1;

    这条语句直接在 DRDS 上执行会报不被支持的错误,但是可以给这条语句加上 DRDS 的自定义 HINT,再提交到 DRDS 执行。具体 SQL 语句如下:

    1. /!TDDL:t1.id=1 and t2.id=1*/UPDATE t1 SET val=(SELECT val FROM t2 WHERE id=1) WHERE id=1;

    这条语句会被下发到t1id为 1 的分库上执行。通过 explain 命令可以看到执行这条 SQL 语句的执行计划:

    1. mysql> explain /!TDDL:t1.id=1 and t2.id=1*/UPDATE t1 SET val=(SELECT val FROM t2 WHERE id=1) WHERE id=1\G
    2. *************************** 1. row ***************************
    3. GROUP_NAME: TEST_DRDS_1485327111630IXLWTEST_DRDS_IGHF_0001_RDS
    4. SQL: UPDATE `t1_2` AS `t1` SET `val` = (SELECT val FROM `t2_2` AS `t2` WHERE `id` = 1) WHERE `id` = 1
    5. PARAMS: {}
    6. *************************** 2. row ***************************
    7. GROUP_NAME: TEST_DRDS_1485327111630IXLWTEST_DRDS_IGHF_0001_RDS
    8. SQL: UPDATE `t1_1` AS `t1` SET `val` = (SELECT val FROM `t2_1` AS `t2` WHERE `id` = 1) WHERE `id` = 1
    9. PARAMS: {}
    10. *************************** 3. row ***************************
    11. GROUP_NAME: TEST_DRDS_1485327111630IXLWTEST_DRDS_IGHF_0001_RDS
    12. SQL: UPDATE `t1_0` AS `t1` SET `val` = (SELECT val FROM `t2_0` AS `t2` WHERE `id` = 1) WHERE `id` = 1
    13. PARAMS: {}
    14. 3 rows in set (0.00 sec)

    explain命令的结果集可以看到,SQL 语句被改写成 3 条语句下发到分库上执行。还可以继续指定分表键值,将 SQL 执行范围缩小到一张分表:

    1. mysql> explain /!TDDL:t1.id=1 and t2.id=1 and t1.name='1'*/UPDATE t1 SET val=(SELECT val FROM t2 WHERE id=1) WHERE id=1\G
    2. *************************** 1. row ***************************
    3. GROUP_NAME: TEST_DRDS_1485327111630IXLWTEST_DRDS_IGHF_0001_RDS
    4. SQL: UPDATE `t1_1` AS `t1` SET `val` = (SELECT val FROM `t2_1` AS `t2` WHERE `id` = 1) WHERE `id` = 1
    5. PARAMS: {}
    6. 1 row in set (0.00 sec)

注意:使用该自定义注释需要保证两张表的分库和分表数量一致,否则 DRDS 计算出的两个键值对应的分库不一致,就会报错。

本文导读目录
本文导读目录
以上内容是否对您有帮助?