1

我有一個TCG卡的數據庫,我試圖決定一個主鍵。最初,我用代理鍵解決了這個問題,但是我意識到,有時候,有些卡片是我忘記添加的,例如促銷卡片。這是代理鍵問題,因爲它們以最新的自動增量添加到數據庫中,並且我不希望它們的ID依賴於它們插入的順序。我在想也許我可以對一些卡的功能進行散列,並將其用作主鍵而不是?crc32作爲主鍵的自然鍵

就拿下面的僞代碼:

// set code, date released, collector number, name 
$crc = crc32(implode(',', ['A', '1993-08-03', '232a', 'black lotus'])); 
echo $crc; // 4199975187 

的卡的數量可能只徘徊25K左右,現在和成長每6個月左右100-300。

  1. 以這樣的速度,不會有碰撞的權利?
  2. 這是一個很好的做法嗎?我有其他好的選擇嗎?

我知道我可以做的哈希通過將其轉換爲base 62短,但我將加入到這些用戶的庫存表所以我想保持這些在int將是最好的選擇。

+0

一般來說,「智能鑰匙」(例如從連接列產生的鑰匙)是一個_bad_想法。你能解釋一下爲什麼'代理鑰匙'不能解決你的問題嗎?密鑰只是一個唯一的數字,如果密鑰的值也恰好對應於插入的順序,它又有什麼關係? – hashbrown 2015-03-25 04:06:40

+0

查看應用程序的用戶將看到「ID」。最有可能在$ _GET參數中。我不希望他們根據他們的ID猜測卡片插入數據庫的順序。 – voldomazta 2015-03-25 04:11:53

+0

爲什麼插入順序對最終用戶有影響?這不像你揭露表名或實際祕密。大多數Web應用程序都使用密鑰的身份。很大比例在某處公開這些密鑰。沒什麼大不了的。 – Tim 2015-03-25 04:32:18

回答

2

我不同意這樣的:

這是與代理鍵的問題,因爲它們被添加到了最新的自動遞增的數據庫,我不希望自己的ID取決於它們的順序插入。

ID(正確:「Id」,因爲它是一個縮寫,而不是初始化)是「Identity」的簡稱,它具有對每個元素唯一的唯一屬性,也就是說,它用於識別每個元素。您不應該附加任何其他含義,因此它隨插入順序單調增加的事實是不相關的,並且通過生成的標識列對數據進行排序沒有意義(除非它位於用於查找ID的索引內)。在這種情況下,您應該將Ids視爲不透明的手柄。

當然,如果你使用摘要(比如CRC-32),Ids的排序順序是沒有意義的,但實際上比單調遞增的Id表現得更少。

您正確識別了散列衝突的風險,CRC-32的範圍空間僅爲32位,如果您擁有25,000個卡片,則生日問題會告訴我們在如此小的範圍內散列衝突的機率空間不是微不足道的。

只需使用自動生成的Id值。 :)

使用計算的散列作爲標識符/鍵具有實用性 - 這就是散列表的工作方式,因爲它允許您快速查找某個值,而無需實際搜索所有表(例如查找黑蓮花牌,像你一樣對其屬性進行哈希處理,然後在ID列中查找計算出的哈希值,而不必執行SELECT ... WHERE code = 'A' AND ... AND name = 'black lotus',但它確實需要您先知道每個屬性值,並且如果設置了正確的表索引這很快就變得沒有意義了。

與使用散列作爲主鍵的主要問題是:

  1. 主鍵應該是不可變的(「永不更改」)
  2. 現在關鍵取決於數據
  3. 如果數據發生變化(例如「blcak lotus」變成「Black Lotus」),那麼這個密鑰是無效的並且必須被重新創建,但是你不能這麼做,因爲密鑰是不可變的......將以前計算的Id無效。

QED :)

+0

很棒的回答。會補充說,良好的主鍵對於正確的索引非常重要,整數在創建索引時效率更高。 – Tim 2015-03-25 04:46:11

+0

@Tim效率增益今天是微不足道的 - 例如,索引4字節整數值的列的成本與4字節的字符值大致相同 - 甚至可以查看「nvarchar(255)」值 - 非常快速地在一個指數中。即使你微調了它(在大多數數據庫應用程序中發生的其他所有事情都是不切實際的情況),但我懷疑你對20個字符左右的字符串會有什麼不同。 – Dai 2017-06-28 23:53:22

+0

這在企業級是錯誤的。有序且均勻分佈的密鑰的重要性在於,當數據量顯着時,以及具有顯着的查詢流量時,數據庫性能日夜不同。如果每秒鐘有幾百行和幾個查詢,則任何密鑰都可以執行。每秒鐘將成千上萬個查詢擴展到數百萬行,並且您的數據庫將使用設計不佳的密鑰進行融合。 – Tim 2017-06-29 00:28:16

-1

研究此鏈接: - http://preshing.com/20110504/hash-collision-probabilities/

你會看到,任何 32位散列和25K加重視碰撞近1比10的賠率 - 不管哈希算法有多好。

您需要一種處理衝突或切換到64位散列算法的機制。根據這個 crc collisions at various bit sizes,CRC64似乎是足夠好的,有1820萬個沒有碰撞的樣本。

+0

雖然您的哈希註釋已被發現,但使用主鍵的天數哈希值是一個非常糟糕的主意。 – Tim 2015-03-25 04:29:04

+0

@蒂姆 - 表面上你是對的。但我懷疑OP可能有一個有效的散列理由(從他的問題中不明顯),無論如何,我想確保這個線程的任何不經意的讀者都不會忘記CRC32是一種很好的方法來派生獨特的鑰匙。 – 2015-03-25 04:43:39