淺析阿里規范中為什么要求表必須有主鍵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的數據結構之后,自然而然就會知道主鍵的重要性,在建表的時候也不會忘記設置主鍵,無論表設計有無合適的唯一字段,都需要設置一個主鍵,提高性能的同時也是一種好的習慣,對於后續的拓展以及表之間關聯都有一定的拓展性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM