位标志法处理多选字段在数据库中的存储方式 查询效率与扩展性之间的权衡
一、位标志法
位标志法(bit flags):把多个选项用一个整数字段(如 INT
或 BIGINT
)存储。
位标志法的优点:
- 存储效率高:只需要一个整数字段(
INT
或BIGINT
)。 - 写入方便:合并多个选项只需要一个整数。
- 快速判断:用位运算判断是否包含某些选项。
- 适合固定选项:如权限、状态、角色等。
位标志法的缺点:
不易扩展 | 最多支持 32(INT)或 64(BIGINT)个选项 |
查询效率低 | 位运算在大数据量下性能不如索引、 |
不易维护 | 查询语句不够直观,需要维护映射表 |
无法统计 | 无法方便地统计某个选项的使用频率 |
无法外键约束 | 不能建立外键引用关系 |
不支持动态选项 | 如果选项频繁变动,维护成本高 |
使用方法:
// 多选值合并为整数字段
public function add() {$bitMap = [1 => 1, // 2^02 => 2, // 2^13 => 4, // 2^24 => 8, // 2^35 => 16, // 2^46 => 32, // 2^57 => 64, // 2^68 => 128, // 2^79 => 256, // 2^810 => 512, // 2^911 => 1024, // 2^1012 => 2048, // 2^1113 => 4096, // 2^1214 => 8192, // 2^1315 => 16384, // 2^14];//合并多选值为一个整数字段$typeValue = $this->combineTypes([1, 3, 6], $bitMap);//解析整数字段为原始多选值$parsed = $this->parseTypes($typeValue, $bitMap); // 得到 [1, 3, 6]
}/*** 合并多选值为一个整数字段(用于保存到数据库)* @param array $selected* @param array $bitMap* @return int*/
public function combineTypes(array $selected, array $bitMap): int {$value = 0;foreach ($selected as $typeId) {if (isset($bitMap[$typeId])) {$value |= $bitMap[$typeId]; // 按位或}}return $value;
}/*** 解析整数字段为原始多选值(从数据库读取)* @param int $value* @param array $bitMap* @return array*/
function parseTypes(int $value, array $bitMap): array {$result = [];foreach ($bitMap as $typeId => $bitValue) {if ($value & $bitValue) {$result[] = $typeId;}}return $result;
}