本文介紹了在5.2及以下版本適用HINT的方法。
基本語法
/!TDDL:hint command*/
PolarDB-X 1.0自定義HINT是借助于MySQL 注釋實現的,也就是PolarDB-X 1.0的自定義HINT語句位于/!
與*/
之間,并且必須以TDDL:
開頭。其中hint command
是PolarDB-X 1.0自定義HINT命令,與具體的操作相關。
例如下面的SQL語句通過PolarDB-X 1.0的自定義HINT展示每個分庫的表名。
/!TDDL:SCAN*/SHOW TABLES;
該SQL語句中/!TDDL:SCAN*/
為PolarDB-X 1.0自定義HINT部分,以TDDL:
開頭,SCAN
為PolarDB-X 1.0自定義HINT命令。
讀寫分離
由于RDS主實例與只讀實例之間數據的同步存在著毫秒級別的延遲,如果在主庫中變更后需要馬上讀取變更的數據,則需要保證將讀取數據的SQL下發到主實例中。針對這種需求,PolarDB-X 1.0提供了讀寫分離自定義HINT,指定將SQL下發到主實例或者只讀實例。
語法
/!TDDL:MASTER|SLAVE*/
在該自定義HINT中可以指定SQL是在主實例上執行還是在只讀實例上執行。對于/!TDDL:SLAVE*/
這個自定義HINT,如果一個主RDS實例存在多個只讀實例,那么PolarDB-X 1.0會根據所分配的權重隨機選擇一個只讀實例執行SQL語句。
示例
- 指定SQL在主實例上執行:
/!TDDL:MASTER*/SELECT * FROM table_name;
在SQL語句前添加
/!TDDL:MASTER*/
這個自定義HINT后,這條SQL將被下發到主實例上執行。 - 指定SQL在只讀實例上執行:
/!TDDL:SLAVE*/SELECT * FROM table_name;
在SQL語句前添加
/!TDDL:SLAVE*/
這個自定義HINT后,這條SQL將會根據所分配的權重被隨機下發到某個只讀實例上執行。
- 此讀寫分離自定義HINT僅僅針對非事務中的讀SQL語句生效,如果SQL語句是寫SQL或者SQL語句在事務中,那么還是會下發到RDS的主實例執行。
- PolarDB-X 1.0針對
/!TDDL:SLAVE*/
自定義HINT,會從只讀實例中按照權重隨機選取一個下發SQL語句執行。若只讀實例不存在時,不會報錯,而是選取主實例執行。
只讀實例延遲切斷
正常情況下,如果給PolarDB-X 1.0數據庫的RDS主實例配置了只讀實例,并且給主實例和只讀實例都設置了讀流量,那么PolarDB-X 1.0會根據讀寫比例將SQL下發到主實例或者是只讀實例執行。但是如果主實例與只讀實例的異步數據復制存在較大的延遲,將SQL下發到只讀實例執行就會導致出錯或者返回錯誤結果。
只讀實例延時切斷會根據主備復制最大延時時間判斷將所執行的SQL下發到主實例還是只讀實例。
語法
/!TDDL:SQL_DELAY_CUTOFF=time*/
在自定義HINT中指定SQL_DELAY_CUTOFF
的值,當備庫的 SQL_DELAY值(MySQL主備復制延遲)達到或超過time
的值(單位秒)時,查詢語句會被下發到主實例。
示例
- 指定主備復制延遲時間為5秒:
/!TDDL:SQL_DELAY_CUTOFF=5*/SELECT * FROM table_name;
在SQL語句指定了
SQL_DELAY_CUTOFF
的值為5,當備庫的SQL_DELAY
值達到或超過5秒時,查詢語句會下發到主實例執行。 - 配合其他自定義HINT使用:
/!TDDL:SLAVE AND SQL_DELAY_CUTOFF=5*/SELECT * FROM table_name;
備庫延遲切斷注釋也可以配合其他注釋使用,該SQL查詢請求默認會被下發到只讀實例,但是當出現主備復制延時達到或超過5秒時,會下發到主實例。
自定義SQL超時時間
在PolarDB-X 1.0中,PolarDB-X 1.0節點與RDS的默認的SQL執行超時時間是900秒(可以調整),但是對于某些特定的慢SQL,其執行時間可能超過了900秒 。針對這種慢SQL,PolarDB-X 1.0提供了調整超時時間的自定義HINT。通過這個自定義HINT可以任意調整SQL執行時長。
語法
/!TDDL:SOCKET_TIMEOUT=time*/
其中,SOCKET_TIMEOUT
的單位是毫秒。通過該 HINT 用戶可以根據業務需要,自由調整SQL語句的超時時間。
示例
設置SQL超時時間為40秒:
/!TDDL:SOCKET_TIMEOUT=40000*/SELECT * FROM t_item;
指定分庫執行SQL
在使用PolarDB-X 1.0的過程中,如果遇到某個PolarDB-X 1.0不支持的SQL語句,可以通過PolarDB-X 1.0提供的自定義HINT,直接將SQL下發到一個或多個分庫上去執行。此外如果需要單獨查詢某個分庫或者已知分庫的某個分表中的數據,也可以使用該自定義HINT,直接將SQL語句下發到分庫中執行。
指定分庫執行SQL自定義HINT有兩種使用方式,即通過分片名指定SQL在分庫上執行或者通過分庫鍵值指定SQL在分庫上執行。其中分片名是PolarDB-X 1.0中分庫的唯一標識,可以通過SHOW NODE
控制指令得到。
語法
/!TDDL:NODE='node_name'*/
node_name
為分片名,通過這個PolarDB-X 1.0自定義HINT,就可以將SQL下發到node_name
對應的分庫中執行。/!TDDL:NODE IN ('node_name'[,'node_name1','node_name2'])*/
使用
in
關鍵字指定多個分片名,將SQL下發到多個分庫上執行,括號內分片名之間使用逗號分隔。說明 使用該自定義HINT時,PolarDB-X 1.0會將SQL直接下發到分庫上執行,所以在SQL語句中,表名必須是該分庫中已經存在的表名。/!TDDL:table_name.partition_key=value [and table_name1.partition_key=value1]*/
在這個PolarDB-X 1.0自定義HINT中
table_name
為邏輯表名,該表是一張拆分表,partition_key
是拆分鍵,value
為指定的拆分鍵的值。在該自定義注釋中,可以使用and
關鍵字指定多個拆分表的拆分鍵。通過這個PolarDB-X 1.0自定義HINT,PolarDB-X 1.0會計算出SQL語句應該在哪些分庫和分表上執行,進而將SQL語句下發到相應的分庫。
示例
對于名為drds_test
的PolarDB-X 1.0數據庫,SHOW NODE
的結果如下:
mysql> SHOW NODE\G
*************************** 1. row ******************
ID: 0
NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0000_RDS
MASTER_READ_COUNT: 212
SLAVE_READ_COUNT: 0
MASTER_READ_PERCENT: 100%
SLAVE_READ_PERCENT: 0%
*************************** 2. row ******************
ID: 1
NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0001_RDS
MASTER_READ_COUNT: 29
SLAVE_READ_COUNT: 0
MASTER_READ_PERCENT: 100%
SLAVE_READ_PERCENT: 0%
*************************** 3. row ******************
ID: 2
NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0002_RDS
MASTER_READ_COUNT: 29
SLAVE_READ_COUNT: 0
MASTER_READ_PERCENT: 100%
SLAVE_READ_PERCENT: 0%
*************************** 4. row ******************
ID: 3
NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0003_RDS
MASTER_READ_COUNT: 29
SLAVE_READ_COUNT: 0
MASTER_READ_PERCENT: 100%
SLAVE_READ_PERCENT: 0%
*************************** 5. row ******************
ID: 4
NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0004_RDS
MASTER_READ_COUNT: 29
SLAVE_READ_COUNT: 0
MASTER_READ_PERCENT: 100%
SLAVE_READ_PERCENT: 0%
*************************** 6. row ******************
ID: 5
NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0005_RDS
MASTER_READ_COUNT: 29
SLAVE_READ_COUNT: 0
MASTER_READ_PERCENT: 100%
SLAVE_READ_PERCENT: 0%
*************************** 7. row ******************
ID: 6
NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0006_RDS
MASTER_READ_COUNT: 29
SLAVE_READ_COUNT: 0
MASTER_READ_PERCENT: 100%
SLAVE_READ_PERCENT: 0%
*************************** 8. row ******************
ID: 7
NAME: DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0007_RDS
MASTER_READ_COUNT: 29
SLAVE_READ_COUNT: 0
MASTER_READ_PERCENT: 100%
SLAVE_READ_PERCENT: 0%
8 rows in set (0.02 sec)
可以看到每個分庫都有NAME
這個屬性,這就是分庫的分片名。每個分片名都唯一對應一個分庫名,比如DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0003_RDS
這個分片名對應的分庫名是drds_test_vtla_0003
。得到了分片名,就可以使用PolarDB-X 1.0的自定義HINT指定分庫執行SQL語句了。
- 指定SQL在第0個分庫上執行:
/!TDDL:NODE='DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0000_RDS'*/SELECT * FROM table_name;
- 指定SQL在多個分庫上執行:
/!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_RDS
,DRDS_TEST_1473471355140LRPRDRDS_TEST_VTLA_0006_RDS
這兩個分片上執行。 - 查看某個分庫的執行計劃:
/!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
語句,PolarDB-X 1.0不支持SET
子句中的子查詢,由于UPDATE
語句在PolarDB-X 1.0中必須指定拆分鍵,所以可以使用PolarDB-X 1.0的自定義HINT將該語句直接下發到分庫上執行。比如有兩張邏輯表,分別是t1和t2,它們都是分庫分表,建表語句如下:
CREATE TABLE `t1` ( `id` bigint(20) NOT NULL, `name` varchar(20) NOT NULL, `val` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by hash(`id`) tbpartition by hash(`name`) tbpartitions 3 CREATE TABLE `t2` ( `id` bigint(20) NOT NULL, `name` varchar(20) NOT NULL, `val` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by hash(`id`) tbpartition by hash(`name`) tbpartitions 3
需要執行的語句是:
UPDATE t1 SET val=(SELECT val FROM t2 WHERE id=1) WHERE id=1;
這條語句直接在PolarDB-X 1.0上執行會報不被支持的錯誤,但是可以給這條語句加上PolarDB-X 1.0的自定義HINT,再提交到PolarDB-X 1.0執行。具體SQL語句如下:
/!TDDL:t1.id=1 and t2.id=1*/UPDATE t1 SET val=(SELECT val FROM t2 WHERE id=1) WHERE id=1;
這條語句會被下發到
t1
的ID
為1的分庫上執行。通過explain命令可以看到執行這條SQL語句的執行計劃: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 *************************** 1. row *************************** GROUP_NAME: TEST_DRDS_1485327111630IXLWTEST_DRDS_IGHF_0001_RDS SQL: UPDATE `t1_2` AS `t1` SET `val` = (SELECT val FROM `t2_2` AS `t2` WHERE `id` = 1) WHERE `id` = 1 PARAMS: {} *************************** 2. row *************************** GROUP_NAME: TEST_DRDS_1485327111630IXLWTEST_DRDS_IGHF_0001_RDS SQL: UPDATE `t1_1` AS `t1` SET `val` = (SELECT val FROM `t2_1` AS `t2` WHERE `id` = 1) WHERE `id` = 1 PARAMS: {} *************************** 3. row *************************** GROUP_NAME: TEST_DRDS_1485327111630IXLWTEST_DRDS_IGHF_0001_RDS SQL: UPDATE `t1_0` AS `t1` SET `val` = (SELECT val FROM `t2_0` AS `t2` WHERE `id` = 1) WHERE `id` = 1 PARAMS: {} 3 rows in set (0.00 sec)
從
explain
命令的結果集可以看到,SQL語句被改寫成3條語句下發到分庫上執行。還可以繼續指定分表鍵值,將SQL執行范圍縮小到一張分表: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 *************************** 1. row *************************** GROUP_NAME: TEST_DRDS_1485327111630IXLWTEST_DRDS_IGHF_0001_RDS SQL: UPDATE `t1_1` AS `t1` SET `val` = (SELECT val FROM `t2_1` AS `t2` WHERE `id` = 1) WHERE `id` = 1 PARAMS: {} 1 row in set (0.00 sec)
掃描全部分庫分表
除了可以將SQL單獨下發到一個或多個分庫執行,PolarDB-X 1.0還提供了掃描全部分庫與分表的自定義HINT。通過這個自定義HINT,您可以一次將SQL下發到每一個分庫執行。比如通過這個自定義HINT,可以查看某個分庫上的所有分表。還可以通過這個自定義HINT,查看某個邏輯表的每個分庫的分表數據量。
掃描全部分片的PolarDB-X 1.0自定義HINT有兩種使用方式,第一種方式是將SQL語句下發到每個分庫執行,第二種方式是將SQL語句下發到每個分庫上對某個邏輯表進行操作。
- 將SQL下發到全部分庫上執行:
/!TDDL:SCAN*/
- 對某個邏輯表進行操作:
/!TDDL:SCAN='table_name'*/
其中
table_name
是PolarDB-X 1.0數據庫的某個邏輯表名。該自定義HINT是為分庫分表提供的,請盡量確保table_name
為分庫分表。