1. 程式人生 > 其它 >淺析阿里規範中為什麼要求表必須有主鍵id:不建主鍵id會有什麼影響

淺析阿里規範中為什麼要求表必須有主鍵id:不建主鍵id會有什麼影響

一、問題背景

  今天在設計表結構的時候,有個記錄表只需要記錄下是誰得了什麼東西,什麼時間得的,也就是3個欄位:user_id、medal_id、created_time,通常表也會加主鍵 id,但是這個表其實不怎麼用到,也就是查詢誰的記錄,或者某東西的記錄時會關聯查一下。你看都沒有 主鍵id 啥事,所以我就有了個疑問,不加 id, 表不是就會小一點嗎,那像這種情況到底需不需要加主鍵id呢?什麼情況下不需要建主鍵id、建與不建的好處各是啥呢?

二、阿里規範中為什麼要求表必須有主鍵id

  資料庫會預設為主鍵欄位建立索引【主鍵索引】。

  那麼如果表中具有多個主鍵,資料庫會不會為每個主鍵都建立索引呢?先建一張表【user:兩個主鍵id,name】

CREATE TABLE `user`  (
  `id` int NOT NULL,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`, `name`)
);
-- 執行命令檢視索引
show index FROM user

  可以看到:資料庫為 id 和 name 都建立了索引。現在終於有點明白阿里規範中為什麼要求建立主鍵id了。但是還是有疑問:那麼難道僅僅只是建立了索引的區別嗎?很多表查詢不用索引查詢,資料量小時,影響也並不大,那麼如果不建主鍵 id 會有什麼影響呢?

三、MySQL InnoDB資料表缺少主鍵會怎樣

1、問題

  MySQL資料表使用InnoDB作為儲存引擎的時候,資料結構就是使用B+樹,而資料本身儲存在主鍵索引上,也就是通常所說的聚簇索引,也就是每個表都需要有個聚簇索引樹,但是,在建表的時候卻發現可以不用指定主鍵,那麼MySQL對於沒有指定主鍵的表示如何處理的呢?

2、InnoDB索引

  對於InnoDB,可以簡單地把所有資料視為索引,每一個索引都對應一個B+數,而主鍵對應的索引就是聚簇索引,表的所有資料都儲存在聚簇索引上,而除了聚簇索引的普通索引儲存的只是主鍵的引用,所以,查詢的時候對於普通索引需要進行回表才能取到具體資料

3、缺少主鍵MySQL如何處理

  既然InnoDB對資料的儲存必須依賴於主鍵,那麼對於沒有建立主鍵的表,該怎麼辦?

  InnoDB對聚簇索引處理如下:

(1)如果定義了主鍵,那麼InnoDB會使用主鍵作為聚簇索引

(2)如果沒有定義主鍵,那麼會使用第一非空的唯一索引(NOT NULL and UNIQUE INDEX)作為聚簇索引

(3)如果既沒有主鍵也找不到合適的非空索引,那麼InnoDB會自動生成一個不可見的名為ROW_ID的列名為GEN_CLUST_INDEX的聚簇索引,該列是一個6位元組的自增數值,隨著插入而自增

  很明顯,缺少主鍵的表,InnoDB會內建一列用於聚簇索引來組織資料。而沒有建立主鍵的話就沒法通過主鍵來進行索引,查詢的時候都是全表掃描,小資料量沒問題,大資料量就會出現效能問題。

  但是,問題真的只是查詢影響嗎?不是的,對於生成的ROW_ID,其自增的實現來源於一個全域性的序列,而所有以ROW_ID為主鍵的表均共享該序列,這也意味著插入的時候生成需要共享一個序列,那麼高併發插入的時候為了保持唯一性就避免不了鎖的競爭,進而影響效能。

4、缺少主鍵或者非空索引存在問題

(1)使用不了主鍵索引,查詢會進行全表掃描

(2)影響資料插入效能,插入資料需要生成ROW_ID,而生成的ROW_ID是全域性共享的,併發會導致鎖競爭,影響效能

5、為每個表設定主鍵

  既然知道InnoDB對資料的儲存和處理都是基於聚簇索引的,那麼,在建表時候要注意主鍵的重要性,為每個表都設定一個主鍵,如果沒有合適的欄位來作為主鍵,可以設定一個業務無關的的代理主鍵,可以是自增ID,也可以是UUID(建議使用自增ID,效能較好)。

6、總結:

  在理解InnoDB的資料結構之後,自然而然就會知道主鍵的重要性,在建表的時候也不會忘記設定主鍵,無論表設計有無合適的唯一欄位,都需要設定一個主鍵,提高效能的同時也是一種好的習慣,對於後續的拓展以及表之間關聯都有一定的拓展性。