本文將介紹STR_HASH函數使用方式。

注意事項

使用STR_HASH做拆分的表僅適用于點查場景,如果在業務中范圍查詢,則會接直接觸發全表掃描導致慢查詢。

使用限制

  • 拆分鍵的數據類型需為字符串類型(CHAR或VARCHAR)。
  • 不支持在建表完成后再調整STR_HASH的參數。
  • PolarDB-X 1.0的實例版本需為5.3.5或以上,關于實例版本請參見版本說明

使用場景

  • 實現一個分表(或分庫)只對應一個拆分表鍵的取值(字符串類型)的精準路由效果。

    例如,某個互聯網金融應用是按年月(YYYYMM)分庫,然后按訂單號分表,該應用的訂單號有個特點,就是訂單號的最后3位字符串是一個整數,其取值范圍是000~999。該應用的需求是需要在一個物理分庫內,要將訂單號后3位的每一個數值只單獨路由到一個物理分表。那么,該應用分庫采用YYYYMM,然后分表采用拆分函數STR_HASH,每個庫1024個分表,就可以達到效果。具體的SQL語句如下:

    create table test_str_hash_tb (    
        id int NOT NULL AUTO_INCREMENT,
        order_id varchar(30) NOT NULL, 
        create_time datetime DEFAULT NULL,
        primary key(id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 
    dbpartition by YYYYMM(`create_time`) 
    tbpartition by STR_HASH(`order_id`, -1, 3, 1) tbpartitions 1024;

    應用采用這樣建表SQL,原因是分表的字符串截取后3位并轉換為整數(整數范圍是000~999)后再取模做分表路由(共1024個分表),其路由結果能保證每一個物理分表只對一個拆分建的取值。而原來默認拆分函數HASH無法達到這樣的效果,是因為字符串經過hashCode計算后的整數是不可預知的,有可能會出現一個物理分表要對應多個不同拆分建的取值。

  • 典型的點查場景

    STR_HASH拆分函數適用于使用字符串類型作為拆分鍵并且是絕大部分都是點查的場景,如根據ID查交易訂單、物流訂單等。

函數定義

STR_HASH函數通過指定字符串的開始位置下標與結束下標,以截取拆分鍵的字符串的某段子串,然后將其作為字符串(或整數)輸入進行分庫分表的路由計算,計算具體的物理分片,具體函數如下所示:

STR_HASH( shardKey [, startIndex, endIndex [, valType [, randSeed ] ] ] )
表 1. 參數說明
參數 說明
shardKey 拆分鍵列的列名。
startIndex 目標子串的開始位置的下標。取值從0開始(即原字符串的第1個字符的下標用0表示),默認值為-1(即不做任何截取)。
endIndex 目標子串的結束位置的下標。取值從0開始(即原字符串的第1個字符的下標用0表示),默認值為-1(即不做任何截取)。
說明 startIndexendIndex時需注意如下幾種取值情況:
  • startIndex == j && endIndex = k (j>=0, k>=0 ,k>j)時,表示截取原字符串的[ j, k )區間的字符串作為子串。例如:
    • 對于字符串ABCDEFG,子串區間[1,5)的值是BCDE
    • 對于字符串ABCDEFG,,子串區間[2,2)的值是''
    • 對于字符串ABCDEFG,子串區間[4,100)的值是EFG
    • 對于字符串 ABCDEFG,子串區間[100,105)的值是''
  • startIndex == -1 && endIndex = k (k>=0)時,表示截取原字符串最后k個字符作為子串,原字符串不足k個字符則直接獲取整個字符串。
  • startIndex = k && endIndex == -1 (k>=0)時,表示截取原字符串開頭k個字符作為子串,原字符串不足k個字符則直接獲取整個字符串。
  • startIndex == -1 && endIndex == -1時, 表示不做任何截取,子串與原字符串完全一致。
valType 表示截取后的子串在計算分庫分表時所使用的類型,取值范圍如下:
  • 0(默認值):表示PolarDB-X 1.0將截取后的子串當作字符串類型來計算路由。
  • 1:表示PolarDB-X 1.0將截取后的子串當作整數類型來計算路由(子串面值的整數不能大于9223372036854775807,也不支持浮點數
randSeed 當子串以字符串類型來計算路由的哈希值時PolarDB-X 1.0所使用的隨機種子的值,通常不用需要填寫,僅當用于使用默認值隨機種子(randSeed=31)的STR_HASH在實際業務中出現路由不均衡的場景,達到用哈希均衡數據的目的。該參數默認值為31,可取其他值(如131,13131,1313131等)。
說明
  • 僅當valType取值為0時,才支持配置該參數。
  • 該參數調整后您需要手動將所有數據導出來,再將新的拆分算法導入數據(即您需要對數據進行重分布)。

使用示例

假設order_id的類型為VARCHAR(32),現在需要將order_id作為拆分鍵,計劃分4個庫,分8個表。

  • 假設需要使用order_id的最后4位的字符串作為整數來計算分庫分表路由,則您可以使用如下SQL進行建表。
    create table test_str_hash_tb (    
        id int NOT NULL AUTO_INCREMENT,
        order_id varchar(32) NOT NULL, 
        create_time datetime DEFAULT NULL,
        primary key(id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 
    dbpartition by STR_HASH(`order_id`, -1, 4, 1) 
    tbpartition by STR_HASH(`order_id`, -1, 4, 1) tbpartitions 2;
  • 假設需要截取order_id的第3個字符(即starIndex=2)與第7個字符(即endIndex=7)之間子串來計算分庫分表路由,則您可以使用如SQL進行建表。
    create table test_str_hash_tb (    
        id int NOT NULL AUTO_INCREMENT,
        order_id varchar(32) NOT NULL, 
        create_time datetime DEFAULT NULL,
        primary key(id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 
    dbpartition by STR_HASH(`order_id`, 2, 7) 
    tbpartition by STR_HASH(`order_id`, 2, 7) tbpartitions 2;
  • 假設需要截取order_id的前5個字符串作為子串來計算分庫分表路由,則您可以使用如SQL進行建表。
    create table test_str_hash_tb (    
        id int NOT NULL AUTO_INCREMENT,
        order_id varchar(32) NOT NULL, 
        create_time datetime DEFAULT NULL,
        primary key(id)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 
    dbpartition by STR_HASH(`order_id`, 5, -1) 
    tbpartition by STR_HASH(`order_id`, 5, -1) tbpartitions 2;

常見問題

Q:dbpartition by STR_HASH(order\_id)dbpartition by HASH(order\_id)有什么區別?

A:兩者雖然都是直接根據字符串取值做分庫分表的哈希路由,但是兩者的分庫分表的路由算法實現不一樣。前者支持用戶建表時自行設定截取子串相關參數,且在根據字符串的哈希值計算分庫分表路由時是基于UNI_HASH算法進行計算;而后者是只對字符串的哈希值做簡單取模。