Mysql

為什麼 MySQL Workbench 允許我向主鍵添加唯一索引?

  • May 5, 2021

我正在使用 MySQL Workbench 8.0.12

複製:

  1. 創建表
  2. 創建第一列id,選擇它作為主鍵(PK)
  3. 在索引下,PRIMARY出現
  4. 回到列下,也選擇id為唯一(UQ)
  5. 在索引下,id_UNIQUE出現

困惑:

  1. 從閱讀MySql - 預設情況下主鍵是否唯一?,我知道主鍵預設意味著唯一性。這與此影片中的傢伙在檢查 PK 後跳過 UQ 的方式一致。最後,這個答案確認在同一列上同時擁有 PK 和 UQ 是多餘的:

如果您將列聲明為 UNIQUE 以及 PRIMARY KEY,那麼 MySQL(Workbench?)奇怪地會在相同的列上創建第二個索引。這確實是多餘的,只會佔用額外的儲存空間,並且在插入/更新/刪除行時會導致一些成本。它沒有任何好處。

  1. 如果這確實對性能有害,並且根據我之前對 MySQL Workbench 的雙重檢查和交叉引用我所做的任何事情的經驗,我想開發人員現在應該做到萬無一失,不讓使用者選擇 UQ on PK頂。例如,通過禁用已選擇 PK 的列上的 UQ 複選框進行通信。既然他們沒有,是不是因為可能存在這樣一種情況,即某人實際上可能在同一列上同時需要 PK 和 UQ?
  2. 為了使這更令人困惑,這個(贊成的)答案說:

使用 UNIQUE CONSTRAINT 來陳述事實。當您有一個恰好是唯一的索引時使用 UNIQUE INDEX,例如因為您將主鍵添加到它。

這意味著這是兩個獨立的狀態。但是,這與 MySQL Workbench 的行為相矛盾,在其中檢查列上的 UQ 將自動創建一個索引,如果您繼續刪除該索引,它會自動取消選擇 UQ。

那麼是否存在極端情況,或者我是否應該牢牢記住在已經PK的專欄上永遠不要考慮UQ,然後繼續前進?

那麼是否存在極端情況,或者我是否應該牢牢記住在已經PK的專欄上永遠不要考慮UQ,然後繼續前進?

我不確定我們能否如此明確。很難對任何事情說“總是”或“從不”。可能有一個我們沒有想到的例外情況。

例如,假設您正在重構一個表。主鍵曾經是,email但現在您希望主鍵是 auto-increment id。因此,您添加新列,刪除主鍵約束,並將主鍵應用於新列:

ALTER TABLE MyTable
 DROP PRIMARY KEY,
 ADD COLUMN id BIGINT AUTO_INCREMENT, 
 ADD PRIMARY KEY (id);

看起來很簡單,對吧?

但是您仍然希望通過email唯一查找進行快速查找,並且您仍然希望阻止使用者使用重複的電子郵件。您還需要測試以確認查詢在使用二級索引時是否具有足夠好的性能,就像使用主鍵(聚集索引)一樣。因此,在刪除目前主鍵之前,您可以在同一列上創建一個二級唯一索引並使用索引提示對其進行測試:

ALTER TABLE MyTable ADD UNIQUE KEY (email);

SELECT ... FROM MyTable USE INDEX (email) WHERE email = '...';

這是一個非常人為的例子,但它並不令人難以置信。關鍵是確實存在邊緣情況,MySQL 項目不希望他們的工具不必要地阻止這種邊緣情況。

根據以下評論編譯的答案:

秋名

當語句語法正確時,沒有理由限制索引創建。最常見的問題 -CREATE TABLE t (id SERIAL PRIMARY KEY);它創建UNIQUE索引(由於SERIAL定義)和PRIMARY KEY(由於顯式指定)。UNIQUE因此,必須通過附加語句刪除多餘的鍵。

  1. 為了使這更令人困惑,這個(贊成的)答案說:

這個問題涉及 SQL Server,不能應用於 MySQL。仔細檢查這些時刻。

那麼是否存在極端情況,或者我是否應該牢牢記住在已經PK的專欄上永遠不要考慮UQ,然後繼續前進?

如果您有 PK,那麼它的表達式始終是唯一的,並且您不需要“在已經 PK 的列上考慮 UQ”。此外,您可以確定 PK 表達式定義中沒有提到任何列(預設情況下,如果列定義中沒有顯式選項,則NULL所有此類列都被隱式定義 - 檢查這一點,小提琴)。NOT NULL``SHOW CREATE TABLE


…和維拉斯

還是我應該牢牢記住在已經PK的專欄上永遠不要考慮UQ,然後繼續前進?

是的,繼續前進!通常,UNIQUE索引用於自然主鍵 - 而您的索引PRIMARY KEY用於代理。純粹主義者不太熱衷於這種方法,但它或多或少是一種行業標準。

在某些情況下,使用代理會減慢系統速度。一個典型的例子是多對多映射表,其中復合 PK 明顯更好。

只是添加一個詞 -UNIQUE自然主鍵的索引應該包括NOT NULL相關欄位的索引 - 可以有一個UNIQUE帶有NULL欄位的索引 - 因為每個欄位NULL既不等於也不等於NULL任何其他值或任何其他值。看看這個小提琴

建議或強制執行“最佳實踐”會是好的 Workbench 嗎?如果您認為是這樣,請將其作為改進送出到 bugs.mysql.com

另一個“建議”: INDEX(a)如果你也有INDEX(a,b).

一個人為的案例: 通過掃描索引的 BTree 而不是掃描BTreeSELECT id FROM tbl;會更有效地執行。前者僅包含,後者包含表的所有列。(如果您在一個子句上附加任何其他列的引用,那麼 PK 的 BTree 將是最佳的。)UNIQUE``PRIMARY KEY's``id``WHERE

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