閱讀146 返回首頁    go 阿裏雲 go 技術社區[雲棲]


阿裏雲 DRDS 分庫分表二維查詢解決方案(RANGE_HASH拆分函數)

現有互聯網業務模式下,數據庫分庫分表已經成為解決數據庫瓶頸的一個普遍的解決方案。分庫分表有多種好處,比如高容量、大並發等,但是在拆分過程中也引入了一些使用限製,比如多維查詢,非拆分鍵的查詢請求會分發到底層所有實例進行查詢,性能會大打折扣。

我們來舉個例子,最常見的訂單表,常用的拆分方法是按照用戶 ID 作為拆分鍵。如果僅使用訂單號作為條件來查詢則會出現上述性能問題,而僅通過訂單號的查詢請求恰恰占有不小的比例。

在阿裏雲提供的新版 DRDS(5.1.28-1320920 及其以上的版本)已經實現二維查詢的功能。看看他的特性 RANGE_HASH(COL1, COL2, N) :

  • 拆分鍵的類型必須是字符類型或數字類型
  • 根據任一拆分鍵後 N 位計算哈希值,然後再按分庫數去取餘,完成路由計算。N 為函數第三個參數。例如:RANGE_HASH(COL1, COL2, N) ,計算時會優先選擇 COL1,截取其後N位進行計算。 COL1 不存在時找 COL2。
  • 適合於需要有兩個拆分鍵,並且查詢時僅有其中一個拆分鍵值的場景。
  • 兩個拆分鍵皆不能修改。
  • 插入數據時如果發現兩個拆分鍵指向不同的分庫或分表時,插入會失敗。

針對上一個例子,使用這個功能就可以解決問題。可以這樣設計訂單表,拆分鍵選擇 user_id & order_id,在 order_id 中冗餘 user_id 後 N 位。這樣使用 RANGE_HASH(user_id, order_id, N) 功能即可以實現僅使用 user_id 或 order_id 條件就可以快速查詢所需要的數據。

DRDS 表結構:

mysql> show create table test_order_rangehash\G
*************************** 1. row ***************************
       Table: test_order_rangehash
Create Table: CREATE TABLE `test_order_rangehash` (
  `id` int(11) NOT NULL AUTO_INCREMENT BY GROUP,
  `user_id` int(11) DEFAULT NULL,
  `order_id` bigint(20) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `auto_shard_key_ORDER_ID` (`order_id`),
  KEY `auto_shard_key_USER_ID` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by RANGE_HASH(`user_id`, `order_id`, 4)

底層數據庫表結構:

mysql>show create table test_order_rangehash\G
*************************** 1. row ***************************
       Table: test_order_rangehash
Create Table: CREATE TABLE `test_order_rangehash` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `order_id` bigint(20) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `auto_shard_key_ORDER_ID` (`order_id`),
  KEY `auto_shard_key_USER_ID` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

拆分鍵所插入值指向不同分庫即會報錯:

mysql> insert into test_order_rangehash (user_id, order_id, create_time) values (100000001, 20170818111111100002,now());
ERROR 4300 (HY000): ERR-CODE: [TDDL-4300][ERR_ROUTE] Route : Range hash has mul rules, insert shard columns must be equal by rule. More: [https://middleware.alibaba-inc.com/faq/faqByFaqCode.html?faqCode=TDDL-4300]

僅使用 user_id 或 order_id 作為查詢條件,均能準確定位到後段數據庫:

mysql> explain select * from test_order_rangehash where user_id = 100000022\G
*************************** 1. row ***************************
GROUP_NAME: DCWEB_1498027405059FQIYDCWEB_JDLT_0022_RDS
       SQL: select `test_order_rangehash`.`id`,`test_order_rangehash`.`user_id`,`test_order_rangehash`.`order_id`,`test_order_rangehash`.`create_time` from `test_order_rangehash` where (`test_order_rangehash`.`user_id` = 100000022)
    PARAMS: {}
1 row in set (0.04 sec)

mysql> explain select * from test_order_rangehash where order_id = 2017081811113220022\G
*************************** 1. row ***************************
GROUP_NAME: DCWEB_1498027405059FQIYDCWEB_JDLT_0022_RDS
       SQL: select `test_order_rangehash`.`id`,`test_order_rangehash`.`user_id`,`test_order_rangehash`.`order_id`,`test_order_rangehash`.`create_time` from `test_order_rangehash` where (`test_order_rangehash`.`order_id` = 2017081811113220022)
    PARAMS: {}
1 row in set (0.03 sec)

結語:多維查詢還可以使用異構索引來實現,但 RANGE_HASH 豈不更好。當然它不是萬能的,某些場景下還是要選擇異構索引(比如訂單表以買家、賣家維度查詢)。

最後更新:2017-08-18 12:32:13

  上一篇:go  高可用的服務注冊中心
  下一篇:go  PostgreSQL SQL 語言:類型轉換