TiDB自增主鍵使用限制及避免方法

2024-12-17 14:56 更新

大家好,我是V 哥,在TiDB中使用自增主鍵時,確實存在一些限制和潛在的熱點問題,今天的文章來聊一聊 TiDB中的自增主鍵要怎么做。

以下是一些使用限制和如何避免它們的方法:

  1. 自增主鍵的限制
    • 必須在主鍵或唯一索引列上定義。
    • 只能定義在整型、FLOAT或DOUBLE類型的列上。
    • 自增列不支持DEFAULT定義。
    • 不支持使用ALTER TABLE增加AUTO_INCREMENT屬性。
    • 默認不允許移除AUTO_INCREMENT屬性,可以通過@@tidb_allow_remove_auto_inc來控制是否允許刪除自增屬性。
    • 可以保證自增不唯一,無法保證順序。

  1. 避免自增主鍵限制的方法
    • 使用AUTO_RANDOM:TiDB提供了AUTO_RANDOM屬性,可以在建表時替代AUTO_INCREMENT使用,這樣TiDB會生成隨機分布的ID,從而避免寫入熱點問題 。
    • 使用SHARD_ROW_ID_BITS:對于非聚簇索引主鍵或沒有主鍵的表,TiDB會使用一個隱式的自增RowID。通過設(shè)置SHARD_ROW_ID_BITS,可以把RowID打散寫入多個不同的Region,緩解寫入熱點問題 。
    • 使用分布式ID生成器:例如Snowflake算法,可以在應(yīng)用層生成唯一的ID,避免依賴數(shù)據(jù)庫的自增主鍵。
    • 使用UUID:可以在應(yīng)用層生成UUID作為主鍵,但需要注意UUID的性能影響。
    • 使用Sequence序列:TiDB支持Sequence序列,可以在創(chuàng)建表時定義Sequence,然后使用Sequence來生成唯一的ID。

使用 AUTO_RANDOM

在TiDB中,AUTO_RANDOM是用于解決自增主鍵熱點問題的一種方法。以下是一個具體的業(yè)務(wù)場景案例和操作步驟:

業(yè)務(wù)場景: 假設(shè)你有一個高并發(fā)的在線服務(wù),需要為每個服務(wù)實例生成一個唯一的標(biāo)識符。如果使用傳統(tǒng)的AUTO_INCREMENT自增主鍵,大量的寫入操作可能會導(dǎo)致寫入熱點,因為所有的寫入都會嘗試在最后一個Region上進行,從而影響性能。

解決方案

  1. 創(chuàng)建表時使用AUTO_RANDOM: 在創(chuàng)建表時,將主鍵列設(shè)置為AUTO_RANDOM。例如,你可以執(zhí)行以下SQL語句來創(chuàng)建一個新表:

   CREATE TABLE service_instances (
       id BIGINT PRIMARY KEY AUTO_RANDOM,
       instance_name VARCHAR(255),
       created_at TIMESTAMP
   );

這樣,每當(dāng)插入新行而沒有指定id值時,TiDB會自動生成一個隨機的id值。

  1. 插入數(shù)據(jù): 當(dāng)插入新服務(wù)實例時,不需要手動指定id值,TiDB會自動為每個實例生成一個唯一的id

   INSERT INTO service_instances (instance_name, created_at) VALUES ('ServiceInstanceName', NOW());

這將利用AUTO_RANDOM屬性生成一個隨機的id,從而避免寫入熱點。

  1. 獲取最后插入的ID: 如果你需要獲取最后插入的id,可以使用LAST_INSERT_ID()函數(shù):

   SELECT LAST_INSERT_ID();

這將返回最近一次由TiDB隱式分配的AUTO_RANDOM值。

咱們可以使用TiDB的監(jiān)控工具,如Grafana,監(jiān)控AUTO_RANDOM字段的性能。注意觀察是否有任何寫入熱點的跡象,如某個TiKV節(jié)點的負載明顯高于其他節(jié)點。根據(jù)監(jiān)控結(jié)果調(diào)整策略。

需要注意的是:

  • 不要顯式地為AUTO_RANDOM字段插入值,除非打開了@@allow_auto_random_explicit_insert系統(tǒng)變量,并且你知道你在做什么。錯誤的顯式賦值可能會導(dǎo)致值耗盡。
  • AUTO_RANDOM只能用于BIGINT類型的主鍵列,并且不支持與AUTO_INCREMENT同時使用。

使用 SHARD_ROW_ID_BITS

業(yè)務(wù)場景案例

假設(shè)你運營一個電商平臺,需要處理大量的訂單數(shù)據(jù)。每個訂單都需要一個唯一的訂單號,而且訂單數(shù)據(jù)寫入數(shù)據(jù)庫時必須均勻分布,以避免寫入熱點。如果使用自增主鍵,大量的寫入操作可能會集中在單個TiKV節(jié)點上,導(dǎo)致寫入熱點問題。

解決方案

  1. 創(chuàng)建非聚簇索引表

創(chuàng)建訂單表時,不使用自增主鍵,而是使用SHARD_ROW_ID_BITS來打散行ID,從而避免寫入熱點。

   CREATE TABLE orders (
       order_id INT PRIMARY KEY NONCLUSTERED,
       product_id INT,
       quantity INT,
       created_at TIMESTAMP,
       INDEX product_idx (product_id)
   ) SHARD_ROW_ID_BITS = 4 PRE_SPLIT_REGIONS=3;

這里SHARD_ROW_ID_BITS = 4表示行ID會被打散到16個分片中,PRE_SPLIT_REGIONS=3表示在表創(chuàng)建后會預(yù)先切分為8個Region。

  1. 插入數(shù)據(jù): 當(dāng)創(chuàng)建訂單時,不需要手動指定order_id,TiDB會自動為每個訂單分配一個唯一的行ID。

   INSERT INTO orders (product_id, quantity, created_at) 
   VALUES (101, 2, NOW());

同樣,我們使用Grafana,監(jiān)控orders表的性能。注意觀察是否有任何寫入熱點的跡象,如某個TiKV節(jié)點的負載明顯高于其他節(jié)點。根據(jù)監(jiān)控結(jié)果調(diào)整SHARD_ROW_ID_BITS的值。

需要注意的是:

  • 不要顯式地為行ID插入值,讓TiDB自動分配。
  • 根據(jù)業(yè)務(wù)并發(fā)度來設(shè)置合適的SHARD_ROW_ID_BITS值,以盡量解決熱點Region無法打散的問題。

問題來了,如何根據(jù)業(yè)務(wù)增長調(diào)整 'SHARD_ROW_ID_BITS' 的值以優(yōu)化數(shù)據(jù)庫性能?

在TiDB中,SHARD_ROW_ID_BITS是一個表屬性,用于設(shè)置隱式_tidb_rowid分片數(shù)量的bit位數(shù),以此來解決寫入熱點問題。這個屬性可以在創(chuàng)建表時指定,也可以用來修改現(xiàn)有表的行為。

調(diào)整SHARD_ROW_ID_BITS值的步驟

  1. 評估當(dāng)前業(yè)務(wù)量和增長趨勢

  • 監(jiān)控當(dāng)前業(yè)務(wù)對數(shù)據(jù)庫的寫入模式和數(shù)據(jù)增長速度。使用Grafana監(jiān)控TiDB的寫入流量和熱點情況。

  1. 決定SHARD_ROW_ID_BITS的值

  • 根據(jù)業(yè)務(wù)增長預(yù)測和當(dāng)前寫入模式,決定一個合適的SHARD_ROW_ID_BITS值。例如,如果當(dāng)前設(shè)置為4(分成16個分片),但寫入壓力仍然很高,可以考慮增加該值。

  1. 修改表屬性

  • 使用ALTER TABLE語句來修改SHARD_ROW_ID_BITS值:

     ALTER TABLE your_table_name SHARD_ROW_ID_BITS = new_value;

  • 其中new_value是你基于業(yè)務(wù)增長評估后決定的新值。

  1. 預(yù)切分區(qū)域

  • 為了確保數(shù)據(jù)能夠均勻分布,可以使用PRE_SPLIT_REGIONS選項在建表后預(yù)先切分出一定數(shù)量的Region:

     CREATE TABLE t (a int, b int) SHARD_ROW_ID_BITS = 4 PRE_SPLIT_REGIONS=3;

  • 這里的PRE_SPLIT_REGIONS=3表示建完表后提前切分出8個Region。

  1. 監(jiān)控調(diào)整后的效果

  • 調(diào)整SHARD_ROW_ID_BITS后,繼續(xù)使用Grafana監(jiān)控系統(tǒng)性能,特別注意寫入流量的分布情況。

  1. 根據(jù)需要進一步調(diào)整

  • 如果寫入熱點仍然存在,可能需要進一步增加SHARD_ROW_ID_BITS的值,或者考慮其他優(yōu)化措施。

需要注意的是:

  • 增加SHARD_ROW_ID_BITS的值會增加Region的分裂數(shù)量,可能會對TiDB集群的性能和資源使用產(chǎn)生影響。
  • 調(diào)整SHARD_ROW_ID_BITS值時,需要確保PD調(diào)度器不會因為小Region合并策略而將Region重新合并。

最后

關(guān)于使用分布式ID生成器,比如雪花算法,還有使用UUID和使用Sequence序列,這里V 哥就不再介紹了,與 MySQL 一致。因此,在 TiDB 中提供了AUTO_RANDOMSHARD_ROW_ID_BITS來解決熱點問題,好用的很。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號