PostgreSQL bitmap组合多个索引
索引在某些场景下能够提升查询性能,比如在字段(a,b)上添加一个索引,对于 where a=5 and b=6 这类查询能够使用该索引提升查询性能,但是另外一个场景 where a=5 or b=6 却不能使用该索引提升性能。
针对以上问题,PostgreSQL 提供了组合多个索引的特性来处理无法通过单个索引扫描实现性能提升的情况,也包括对同一个索引的多次使用。比如 where x=1 or x = 3 or x = 5 or x =10,这类查询可以分解为对 x 字段索引的四次单独扫描,每次扫描使用一个查询子句,然后将四次扫描的结果进行逻辑或运算产生最终结果。
另外一个例子,在字段 x,y 上有两个单独的索引,对于 where x=5 and y=6 这类查询,可以分解为 x=5 扫描 x 字段的索引,y=6 扫描 y 字段的索引,然后将结果进行逻辑与运算产生最终结果。
为了组合多个索引,数据库内核扫描每个单独的索引,并在内存中设置一个 bitmap,记录索引匹配到的表行的位置,然后根据查询的需要将 bitmap 进行逻辑 or 或者 and 运算,返回运算后的最终结果。bitmap 的机制使得最终的表行按物理顺序访问,这就会导致原始索引的任何排序都将丢失,因此如果查询有 order by 子句,则需要单独的排序步骤,这会导致额外的时间成本。
在实际应用开发中,通常有很多种索引组合可以使用,开发人员需要权衡。有时多列索引是最好的,有时单列索引配合索引组合特性是最好的。比如业务查询涉及两个字段 x 和 y,有时只单独查询 x 或 y,有时查询会同时涉及 x 和 y。那么可以考虑创建索引 (x),(y),或者 (x,y)。
- 如果仅创建 (x,y)索引,那么对于只涉及 y 字段的查询则用不到该索引
- 如果创建(x),(y)两个单列索引,则可以使用组合多个索引特性,覆盖所有查询类型
- 如果创建(x,y)和(y),能够覆盖所有查询类型,但对于只涉及 x 的查询,要比单列(x)索引慢一些
- 如果创建(x),(y),(x,y),能够覆盖所有查询类型,但是在表更新场景下会影响性能
总结:
索引能够提升特定场景下的查询性能,索引方案有很多种,bitmap 组合多个索引的特性在查询条件包含多个逻辑 or 或 and 场景下能够有效提升性能,开发人员应当根据具体的场景类型进行权衡选择。