bitmap索引是为低基数列设计的快速布尔查询结构,将每个唯一值映射为位图,适合性别、状态等少量枚举值场景;不适合高基数列如用户id或时间戳。

什么是 Bitmap 索引,它适合什么场景
Bitmap 索引不是通用容器,而是为「低基数列」(比如性别、状态、是否启用)做快速布尔查询而设计的。它把每个唯一值映射成一个 std::vector<bool></bool> 或 std::bitset,每一位代表某行是否等于该值。查 "status = 'active'" 就是取对应位图做遍历或位运算,比 B+ 树快得多——但千万别拿它存用户 ID 或时间戳。
用 std::bitset 实现固定长度位图索引
如果知道总行数(比如 100 万条记录),std::bitset 是最轻量的选择:内存紧凑、支持 & | ^ 原生位运算,且编译期大小确定。
示例:建一个表示「是否已删除」的位图索引
class BitmapIndex {
std::bitset deleted_;
public:
void set_deleted(size_t row_id) { deleted_.set(row_id); }
void clear_deleted(size_t row_id) { deleted_.reset(row_id); }
bool is_deleted(size_t row_id) const { return deleted_[row_id]; }
// AND 查询:返回所有既 deleted 又 active 的行 ID(需配合其他索引)
std::bitset and_with(const std::bitset& other) const {
return deleted_ & other;
}
};
注意:std::bitset 大小必须是编译期常量,不能动态扩容;超过栈限制(通常几 MB)时,得用 std::vector<uint64_t></uint64_t> 手动管理位操作。
用 std::vector<uint64_t></uint64_t> 支持动态行数
实际系统中行数未知或会增长,推荐用 uint64_t 数组模拟位图:每 64 行共用一个 word,通过 word_idx = row_id / 64 和 bit_offset = row_id % 64 定位。
关键点:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
resize((max_row_id + 63) / 64)控制容量,别直接resize(max_row_id) - 设置位:
words[word_idx] |= (1ULL —— 必须用 <code>ULL避免左移溢出 int - 清零位:
words[word_idx] &= ~(1ULL - 读取位:
(words[word_idx] >> bit_offset) & 1 - AND/OR 操作要循环每个 word,不能直接
std::vector::operator&
错误常见于:忘记 ULL 导致高位丢失;row_id 超出当前分配范围却没扩容;未对齐访问(其实不影响正确性,但影响 cache 局部性)。
如何关联值到位图(Value → Bitmap 映射)
Bitmap 索引本质是「值字典 + 位图数组」。不要用 std::map<:string bitmap></:string> 存原始字符串——字符串比较慢,且重复值多时浪费空间。
更合理的做法:
- 先对原始列去重并排序,生成
std::vector<:string> values_</:string> - 用
std::unordered_map<:string size_t></:string>做值到下标(即 bitmap index)的 O(1) 查找 - 每个下标对应一个
std::vector<uint64_t></uint64_t>位图 - 插入新值时,先查 map,不存在则 push_back 到 values_ 并分配新 bitmap
性能陷阱:频繁增删值会导致位图数量爆炸,此时应考虑 Roaring Bitmap 等压缩结构——但那是进阶需求,简单实现里先守住「值种类 ≤ 1000」这个线。
位图索引真正难的不是位操作本身,而是和主表行号对齐、事务一致性、以及增量更新时如何避免全量重建。这些在原型阶段容易被忽略,等数据量上万就暴露了。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










