Mysql

雜湊 ID(例如 base64 YouTube 影片 ID):儲存為 int/bigint 或字元串,為什麼?

  • June 6, 2020

我想生成“不可猜測”的 ID,而不是 /record/1、/record/2、/record/3 等。

YouTube 使用 base 64 的風格允許以 4 個字元 (64 * 64 * 64 * 64) 儲存 1670 萬個 ID。這對我的需求來說已經綽綽有餘了。

我唯一的想法是我是否應該將它們作為整數儲存在數據庫中並在每次請求進入時(或者當我需要生成 url 時)進行轉換,或者將它們儲存為使用者將看到的字元串。為什麼?

幾個後續問題:

1)而不是生成隨機整數並將它們轉換為base64字元串,我應該使用帶有鹽的自動遞增數字來隨機化字母表,這樣我就可以從1 2 3 4 5 6 7等的ID中獲得明顯的“隨機”標識符. 為什麼?

  1. 對於表關係,我應該使用我生成的任何內容作為我的 PK/FK,還是應該是一個單獨的列並且只是一個簡單的自動增量 int,出於某種原因?

在 SQL Server 中,我會將其儲存為int, 並用於CRYPT_GEN_RANDOM(4)為每一行生成加密隨機數。

這是一個例子:

DECLARE @c int;
DECLARE @c_base64 varchar(8);
DECLARE @c_converted int;

--get the cryptographically random integer
SELECT @c = CONVERT(int, crypt_gen_random(4));
--convert it into a base-64 string
DECLARE @c int;
DECLARE @c_base64 varchar(8);
DECLARE @c_converted int;

--get the cryptographically random integer
SELECT @c = CONVERT(int, crypt_gen_random(4));
--convert it into a base-64 string
SELECT @c_base64 = (SELECT CONVERT(varbinary(4), @c) FOR XML PATH(''), BINARY BASE64);
--convert it back to an int
SELECT @c_converted = CONVERT(int, (CONVERT(xml, @c_base64).value('.', 'varbinary(4)')));
--display the original, the string, and the converted string
SELECT original = @c, converted = @c_base64, unconverted = @c_converted;

結果如下所示:

+-----------+-----------+-------------+
| 原創 | 轉換 | 未轉換 |
+-----------+-----------+-------------+
| 629493479 | JYVO5w == | 629493479 |
+-----------+-----------+-------------+

為什麼?儲存整數將佔用儲存轉換後字元串的一半空間。這在磁碟上可能看起來不多,但是如果您有一個包含 50 億行的表,那麼每個字節都很重要。每行浪費 2 個字節意味著您需要額外千兆字節的 RAM 來掃描這種情況下的表。

您正在尋找的解決方案

16M 可以儲存在一個 3 字節的MEDIUMINT UNSIGNED.

一個 4 字元的 base64 可以儲存在一個 4 字節的CHAR(4) CHARACTER SET ascii COLLATE ascii_bin.

1 字節的差異可能不到所消耗磁碟空間的 1%——不值得擔心。

在 mediumint 和 char 之間進行動態轉換可能消耗不到 1% 的 CPU 時間。

mediuming vs char(4) 的性能——也是一個微小的差異。

我有一條經驗法則:如果提議的更改不能將某些指標(通常是速度或空間)提高至少 10%,我會放棄它。相反,我選擇更容易程式的東西。

替代解決方案

但是……我質疑base64的使用。如果尾隨=顯示,那麼使用者會猜測它是 base64,轉換為 int,並且你的封面被吹了,至少如果你使用的是序列號。

如果您使用的是“隨機”數字,請考慮使用更大的範圍(4 字節 INT / CHAR(5) / 其他)並使用MD5(CONCAT('secret salt', sequence))然後剝離 30 位。這不能“反轉”,但您可能不需要從密鑰中獲取原始 int 。

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