Mysql

為什麼 MySQL 的唯一鍵末尾沒有主鍵?

  • September 19, 2019

我有一個具有以下定義的表。

CREATE TABLE `test` (
 `a` int(11) NOT NULL,
 `b` int(11) DEFAULT NULL,
 `c` int(11) DEFAULT NULL,
 `d` int(11) DEFAULT NULL,
 `e` int(11) DEFAULT NULL,
 `f` int(11) DEFAULT NULL,
 `g` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
 `h` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
 PRIMARY KEY (`a`),
 UNIQUE KEY `b_UNIQUE` (`b`),
 KEY `single` (`c`),
 KEY `double` (`d`,`e`),
 KEY `triple` (`f`,`g`,`h`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

對於某些查詢,當我檢查優化器跟踪時,我注意到索引的關鍵部分。

例如:

{
 "index": "single",
 "usable": true,
 "key_parts": [
   "c",
   "a"
 ]
},
{
 "index": "double",
 "usable": true,
 "key_parts": [
   "d",
   "e",
   "a"
 ]
}

注意索引singledouble關鍵部分最後包含主鍵a。就是這麼InnoDB說的。所以這很好。

{
 "index": "b_UNIQUE",
 "usable": true,
 "key_parts": [
   "b"
 ]
}

但如上面的程式碼片段所示,b_Unique鍵不包含主鍵a作為最終鍵部分。它真的不存在並且存在指向記錄的指針嗎?這對查詢優化和頁面重組有什麼影響?

編輯 1:它似乎存在於 MySQL 8.0 版本中。它也很可能出現在 MySQL 5.7 版中。所以需要一種方法來檢查它在這個版本中的存在。

但如上面的程式碼片段所示,b_Unique 鍵不包含主鍵 a 作為最終鍵部分。

這是一個片段問題。

show index from test
表 | 非唯一 | 鍵名 | Seq_in_index | 列名 | 整理 | 基數| 子部分 | 包裝 | 空 | 索引類型 | 評論 | 索引評論 | 可見 | 表達
:---- | ---------: | :------- | -----------: | :---------- | :-------- | ----------: | -------: | :----- | :--- | :--------- | :------ | :------------ | :------ | :---------
測試 | 0 | 初級 | 1 | 一個 | 一個 | 0 | *空*| *空* | | BTREE | | | 是 | *空* 
測試 | 0 | b_UNIQUE | 1 | 乙 | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 1 | 單身 | 1 | c | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空值* 
測試 | 1 | 雙 | 1 | d | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 1 | 雙 | 2 | 電子| 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 1 | 三重 | 1 | f | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空值* 
測試 | 1 | 三重 | 2 | 克 | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 1 | 三重 | 3 | h | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空值*      
show extended index from test
表 | 非唯一 | 鍵名 | Seq_in_index | 列名 | 整理 | 基數| 子部分 | 包裝 | 空 | 索引類型 | 評論 | 索引評論 | 可見 | 表達
:---- | ---------: | :------- | -----------: | :---------- | :-------- | ----------: | -------: | :----- | :--- | :--------- | :------ | :------------ | :------ | :---------
測試 | 0 | 初級 | 1 | 一個 | 一個 | 0 | *空*| *空* | | BTREE | | | 是 | *空* 
測試 | 0 | 初級 | 2 | DB_TRX_ID | 一個 | *空*| *空*| *空* | | BTREE | | | 是 | *空* 
測試 | 0 | 初級 | 3 | DB_ROLL_PTR | 一個 | *空*| *空*| *空* | | BTREE | | | 是 | *空值* 
測試 | 0 | 初級 | 4 | 乙 | 一個 | *空*| *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 0 | 初級 | 5 | c | 一個 | *空*| *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 0 | 初級 | 6 | d | 一個 | *空*| *空*| *空* | 是 | BTREE | | | 是 | *空值* 
測試 | 0 | 初級 | 7 | 電子| 一個 | *空*| *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 0 | 初級 | 8 | f | 一個 | *空*| *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 0 | 初級 | 9 | 克 | 一個 | *空*| *空*| *空* | 是 | BTREE | | | 是 | *空值* 
測試 | 0 | 初級 | 10 | h | 一個 | *空*| *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 0 | b_UNIQUE | 1 | 乙 | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 0 | b_UNIQUE | 2 | 一個 | 一個 | *空*| *空*| *空* | | BTREE | | | 是 | *空值* 
測試 | 1 | 單身 | 1 | c | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 1 | 單身 | 2 | 一個 | 一個 | *空*| *空*| *空* | | BTREE | | | 是 | *空* 
測試 | 1 | 雙 | 1 | d | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空值* 
測試 | 1 | 雙 | 2 | 電子| 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 1 | 雙 | 3 | 一個 | 一個 | *空*| *空*| *空* | | BTREE | | | 是 | *空* 
測試 | 1 | 三重 | 1 | f | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空值* 
測試 | 1 | 三重 | 2 | 克 | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 1 | 三重 | 3 | h | 一個 | 0 | *空*| *空* | 是 | BTREE | | | 是 | *空* 
測試 | 1 | 三重 | 4 | 一個 | 一個 | *空*| *空*| *空* | | BTREE | | | 是 | *空值*      

您創建的任何唯一鍵都不需要主鍵。

8.5 多年前,我回答了為什麼主鍵有自己的名字?. 我描述了主鍵實際上與唯一鍵沒有什麼不同,因為所有唯一鍵(在數據庫理論中被稱為候選鍵)都為表中的每一行定義了一個唯一性級別。

例如,一個員工表可能有一個員工 ID 號和一個社會保險號。每個值唯一標識一個員工。使主鍵與唯一鍵不同的原因嚴格來說是通過應用程序使用的選擇問題。主鍵只是用於引用和辨識表行的預設候選鍵。二級索引將通過 PRIMARY Key 來確定它檢索的每一行。

唯一鍵還可以規定輸入表格的數據的嚴格性。假設您想確保表中的三列對於表行是唯一的。將數據輸入表格後,您是否總是在表格中查找包含三列(來自唯一鍵)或一列(主鍵)的行?自然,使用最少的列是有意義的。

關於您的桌子,您可以輕鬆地將其設計為

CREATE TABLE `test` (
 `a` int(11) NOT NULL,
 `b` int(11) DEFAULT NULL,
 `c` int(11) DEFAULT NULL,
 `d` int(11) DEFAULT NULL,
 `e` int(11) DEFAULT NULL,
 `f` int(11) DEFAULT NULL,
 `g` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
 `h` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
 PRIMARY KEY (`b`),
 UNIQUE KEY `a_UNIQUE` (`a`),
 KEY `single` (`c`),
 KEY `double` (`d`,`e`),
 KEY `triple` (`f`,`g`,`h`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

並且所有 SELECT 查詢都會在查詢優化器中以相同的方式機械地查找數據。

注意事項:盡可能避免使用多列主鍵,因為較大的主鍵會使所有輔助鍵膨脹。請閱讀 MySQL Docs on Clustered Indexes 了解更多資訊

引用自:https://dba.stackexchange.com/questions/249153