Primary-Key

不暴露業務內部的高效主鍵

  • September 13, 2018

auto_increment primary key用來儲存使用者執行的每個任務。使用者將獲得執行有關其任務的查詢的密鑰。密鑰短而高效,但會以可預測的方式自動遞增。

如果使用者創建了 2 個任務並獲得了一個自動遞增的鍵,那麼他可以計算在該時間間隔內發生了多少任務,從而給他帶來了不必要的洞察力。

為了解決這個問題,我考慮使用UUIDs 代替 auto_incremented 鍵。但這也有它的缺點。當破折號被剝離時,它的 32 個字元長,據我所知,它對性能有很大的影響。有問題的表不會超過一百萬行,所以我不確定這是如何應用的。

UUID 的最後一部分是節點的 MAC 地址。我將只使用 1 台機器,因此可以剝離該部分,使其變為 20 個字元。

我目前最喜歡的選擇是使用類似的東西SELECT FLOOR(rand() * 10000000000); ,而不是檢查該號碼是否已經存在。

我應該考慮儲存不可預測的主鍵的任何其他方法嗎?您推薦哪個選項?

首先確保使用者不知道這些資訊是很重要的。*如果他們知道在他們最後兩個任務之間記錄了 12 個其他任務,這真的有問題嗎?*他們可以用這些會導致問題的資訊做什麼?

如果您擔心他們可能會通過調整客戶端請求(要求 getdata.php?recordid=1233,其他人的記錄,而不是 getdata.php?recordid=1234,他們的記錄之一)來訪問他們應該訪問的數據,那麼問題不在於知道存在其他記錄,而在於應用程序沒有正確驗證請求和/或執行檢查安全性。如果是這種情況,那麼您可以通過對每個請求進行請求偽造檢查和/或權限檢查來解決應用程序層的問題(我不會在這裡詳細介紹這些問題,因為它遠離了問題的核心主題) .

如果對使用遞增數字存在合理的擔憂,那麼與您試圖解決的問題相比,UUID 所需的額外儲存真的那麼昂貴嗎?

您沒有說明您正在使用哪個數據庫引擎,但部分問題強烈建議使用 mySQL。其他數據庫可以通過將 UUID 作為原生二進制類型處理來更好地處理 UUID,佔用 16 個字節而不是 32 個字元。我使用 mySQL 已經有一段時間了,現代版本是否支持這個或類似的?儘管如此,這仍然是整數大小的四倍。

您可以通過位交換來轉換應用程序層中的密鑰:每次發送 ID 時,客戶端都會切換位(將位 1 與位 3 交換,位 4 與位 0,…)並在接收到 ID 時轉換回來在使用它們查詢數據庫之前。這意味著您在不改變數據儲存效率的情況下混淆了 ID,但是您在應用程序中添加了額外的複雜性和潛在的錯誤和低效率。經驗豐富的黑客可能會看穿這種混淆,特別是考慮到要分析的大量數據,但不太確定的人只會看到一組隨機/任意數字。您還可以使用其他這樣的翻譯:移動 8 位的數量並用原始數字的簡單散列填充底部 8。

將“縮放並在底部添加一些隨機位”的想法推送到數據庫中,您可以擁有一個組合鍵,即自動增量值加上另一個整數或 smallint,其值預設為任意/隨機值。在 SQL Server 中,您可以通過使用使用者定義的序列來填充 BIGINT 列在一個列中執行此操作,其他 DB 可能會提供類似的東西,儘管對於許多插入來說,這裡會考慮性能。事實上,即使沒有更大的類型和隨機性,數據模型中所有增量共享的序列也可能會產生您正在尋找的混淆效果。

有許多富有想像力的方法可以使您的密鑰更加任意,但它們都在數據庫或應用程序的某個地方增加了複雜性,所以我會回到我最初的回答:你真的需要嗎?如果需要是真實的,那麼我傾向於硬著頭皮使用 UUID,輸入完全任意的 4 UUID,而不是包含 MAC 的類型 1,因此有一些順序,如果不是,我會堅持使用增量整數為了效率。

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