在處理「不連續、離散的集合數據」時,傳統方案多用字符串拼接(如 10-20|25|29-40)或多字段存儲。但隨著業務複雜度提升,解析、查詢、存儲開銷逐漸成為瓶頸。本文介紹一種極簡高效的替代方案——01 字串(位圖/Bitmap)編碼,並通過三個實戰場景演示其優勢與權衡。
假設業務範圍為 1-100 歲,用 100 個字符的字串表示,第 i 位為 1 表示存在年齡 i,0 表示不存在。例如:
0111111000 => 代表 2-7 歲(索引 1-6 為 1) 0110111010 => 代表 2-3、5-7、9 歲
這本質上是 位圖(Bitmap)的字符串化表達,將集合運算轉化為字符串/位運算,極大簡化邏輯。
需求:支援 10-20、25、29-40 這類任意離散區間組合。
傳統方案痛點: 需自定義解析規則,篩選時需拆分字符串、遍歷區間、逐個判斷,代碼冗長且易出錯。
01 字串方案:
// 初始化:100 個 0
$ageBitmap = str_repeat('0', 100);
// 設置區間函數
function setRange(&$bitmap, $start, $end) {
for ($i = $start; $i <= $end; $i++) {
$bitmap[$i - 1] = '1'; // 字符串可直接按索引修改(PHP 7.1+)
}
}
// 使用
setRange($ageBitmap, 10, 20);
setRange($ageBitmap, 25, 25);
setRange($ageBitmap, 29, 40);
// 判斷某年齡是否包含:O(1)
function hasAge($bitmap, $age) {
return $bitmap[$age - 1] === '1';
}
優勢: 設置/查詢均為 O(1) 或 O(區間長度),無需解析邏輯,代碼極簡。
需求:從 1-200 中隨機選取若干數字,需在前後端傳輸或持久化。
傳統方案: 1|5|100|199 字符串,數量越多越長,解析仍需 explode + 遍歷。
01 字串方案: 固定 200 字符,1 表示被選中。網絡傳輸固定長度,解析極快:
// 生成:隨機選 10 個數
$bitmap = str_repeat('0', 200);
$selected = [];
while (count($selected) < 10) {
$n = mt_rand(1, 200);
if ($bitmap[$n-1] === '0') {
$bitmap[$n-1] = '1';
$selected[] = $n;
}
}
// 傳輸:直接發送 $bitmap 字符串(200 bytes)
// 接收端判斷:$bitmap[99] === '1' 即知 100 被選中
需求:表示 [1926, 19658, 12, 5638, 8975, 965, 369, 5126, 5698, 14556] 這類稀疏、跨度極大的 ID 集合。直接用 19658 位字串極其浪費。
映射壓縮方案:
[1=>1926, 2=>19658, 3=>12, ...]1010000010 代表選中 1、3、9 號映射項// 映射表(雙方約定或首次下發)
$map = [1926, 19658, 12, 5638, 8975, 965, 369, 5126, 5698, 14556];
// 狀態字串(高頻變更、傳輸)
$state = '1010000010'; // 選中 1926、12、5698
// 解碼
$selectedIds = [];
for ($i = 0; $i < strlen($state); $i++) {
if ($state[$i] === '1') $selectedIds[] = $map[$i];
}
// 結果:[1926, 12, 5698]
此法極大節省頻寬,尤其適合 WebSocket 長連接、MQTT 物聯網場景的高頻狀態同步。
| 維度 | 01 字串 | 傳統字符串/JSON | 數據庫關聯表 |
|---|---|---|---|
| 存儲空間 | 固定、極小(位級) | 隨數據量線性增長 | 標準化、可索引 |
| 查詢/判斷速度 | 極快(O(1) 索引/位運算) | 需解析遍歷 | 需 JOIN/子查詢 |
| 開發複雜度 | 低(核心邏輯極簡) | 中(需解析器) | 高(遷移、維護) |
| 適用場景 | 範圍固定、高頻讀寫、離散集合 | 結構不固定、低頻 | 關聯查詢複雜、需事務 |
| 局限性 | 範圍不可動態擴展、稀疏需映射 | 通用性強 | 最通用 |
建議: 當集合範圍明確(如 1-100 歲、1-288 時段、固定權限點)、讀寫頻率高、且主要操作是「判斷屬於/不屬於」「並集/交集/差集」時,01 字串是極佳選擇。若範圍動態變化大、或需複雜關聯查詢,仍建議用標準關聯表或 JSON 字段(MySQL 5.7+/PostgreSQL 支援 JSON 索引)。
位圖思想不僅限於字符串,PHP 還提供 gmp_init()、gmp_setbit() 等 GMP 大整數函數,可直接進行位運算(AND/OR/XOR),性能更強。對於千萬級位圖,建議使用 Redis Bitmap(SETBIT/GETBIT/BITOP)實現分佈式高性能集合運算。