B+Tree 索引存儲長字串(URL、JSON、Base64)體積大、比較慢。利用哈希值(CRC32、MD5 截斷、FNV64)建立整數索引,可大幅縮小索引體積、提升查詢速度。本文詳細說明實作步驟、碰撞處理與函數選型建議。
CREATE TABLE url ( id BIGINT PRIMARY KEY AUTO_INCREMENT, url VARCHAR(2048) NOT NULL, INDEX idx_url (url) -- 索引巨大,比較慢 ); -- 查詢 SELECT id FROM url WHERE url = 'https://www.example.com/very/long/path...';
url_crc INT UNSIGNED 欄位,存 CRC32(url)INDEX idx_url_crc (url_crc)SELECT id FROM url
WHERE url_crc = CRC32('https://www.example.com/...')
AND url = 'https://www.example.com/...';
| 函數 | 輸出 | 長度 | 速度 | 碰撞率 | 建議 |
|---|---|---|---|---|---|
| CRC32() | 32-bit 無號整數 | 4 bytes | 極快 | ~1% at 93k rows | 中小表首選 |
| MD5() 截取 16 字元 | 64-bit 整數 | 8 bytes | 較慢 | 極低 | 大表可用 |
| SHA1() | 160-bit 字串 | 40 chars | 慢 | 極低 | 不建議(太長) |
| FNV64 (UDF) | 64-bit 整數 | 8 bytes | 極快 | 極低 | 高效能場景首選 |
-- 取 MD5 後 16 字元轉 10 進位 64-bit 整數
SELECT CONV(RIGHT(MD5('https://example.com'), 16), 16, 10) AS hash64;
-- 結果:12345678901234567890
-- 正確:哈希 + 原值雙重驗證
SELECT id FROM url
WHERE url_crc = CRC32('target_url')
AND url = 'target_url';
-- 錯誤:僅用哈希,碰撞時返回錯誤資料
SELECT id FROM url WHERE url_crc = CRC32('target_url');
生日悖論:CRC32 32-bit 空間,9.3 萬行碰撞機率達 1%。必須雙重驗證。
| 方式 | 優點 | 缺點 |
|---|---|---|
| 應用層寫入時計算 | 簡單、無額外負載 | 需修改所有寫入路徑 |
| 觸發器 | 資料庫層強制一致 | 增加寫入延遲、除錯難 |
| Generated Column (MySQL 5.7+) | 自動計算、可建索引、無觸發器開銷 | 需 5.7+ |