人是有惯性的。对于使用数据库的人来说,他们习惯于使用索引。大多数人只知道我们可以使用索引来改善数据访问。表现。至于索引是如何实现的,大家可能也知道,只需要将索引数据的B+TREE存储在叶子节点中,就可以快速定位到数据所在的位置,然后从表中获取数据,从而实现一个与全表扫描相比,更快获取数据的目的。但是,带着惯性,我们一直在将我们的业务模型与B-tree进行整合,试图让我们的应用程序的数据访问方式更符合B-tree的结构,从而获得更好的性能。比如控件不会出现在索引中,那么我们创建一个如(col,1)这样的索引,这样索引中也可以包含col的空值记录。比如当我们的索引字段的独立值个数比较少的时候,我们会发现使用索引可能没有全表扫描快,而使用位图索引时容易出现锁放大的性能问题并发写入。如果我们只访问表中占少量记录的几个值,我们发现可以使用B树索引来提高性能。只是我们创建的索引包含了所有数据的索引值,这对应用程序是没有用的。其实在使用索引的时候,我们忘记了使用索引的目的是为了更快的找到数据。索引不仅是B树或位图。索引是一种辅助数据结构。事实上,它们可以定义为任何样式。例如,只是为了解决某个SQL中几个表之间的复杂关系,或者只是为了快速找到某个应用程序需要的数据。您可以设计最适合应用程序特性的索引结构来加速此类应用程序。其实有一类索引对表关联查询特别有效。这种索引已经出现几十年了,我们可能从来没有用过,就是连接位图索引BMJ。这种索引在OLAP系统中可能用的比较多,在OLTP系统中很少用到,因为会影响DML的性能。但是,如果你的数据写入后很少变化,并且并发写入没有明显的瓶颈,那么BMJ在OLTP中使用也是安全的。BMJ是专门用于表连接的索引,其性能高于一般的HASHJOIN或NL。如果您使用的是PostgreSQL数据库,您会对索引设计既兴奋又困惑。PG数据库的索引类型太丰富了。即使我们排除一些全文检索的索引类,JSON.我们还可以找到许多有趣的索引类型。比如我们上面的例子,每次我们只从上亿条数据中找出几百条特殊数据,那么我们就可以在PG中使用偏索引(PartialIndex)。我们可以把这个索引看成一个特殊的函数索引,它的存储结构也是B-TREE。部分索引,也称为过滤索引,只覆盖表数据的一个子集,是一种带有WHERE子句的索引。部分索引有助于在减小索引大小的同时加快查询速度,这些索引需要更少的存储空间,更易于维护,并且扫描速度更快。比如一张表,STATUS=001的数据就是我们需要SELECT处理的。经过处理,STATUS变成了002,所以这张表的STATUS字段的取值范围是倾斜的,001可能只有几条记录。几百条记录,而002有几千万条记录。在PostgreSQL中,我们可以使用Partial索引取得更好的效果。在t_order(status)上创建索引idx_partial_status,其中status='001';这个索引中只有status='001'的数据,所以索引很小。访问效率也很高。为了使它更复杂,我们可以像这样创建一个PartialIndex。在t_order(status)上创建索引idx_partial_status,其中statusin('001','002');如果我们的where条件是statusin('001','002'),那么这个索引就可以工作。另一种有趣的PG索引类型是覆盖索引。在Oracle数据库中,对于大量回表数据的查询,如果不回表的话,性能会有很大的提升。对于这种情况,Oracle有两种解决方法。一种是创建一个包含所有返回字段的索引,使执行计划变成INDEXONLYSCAN,从而提高性能。但是,如果返回的字段数很大,那么索引的冗余部分就会很多,有时我们只能使用索引组织表(IOT)来代替索引。实际上,在SQL中可能用于定位数据的WHERE条件中出现的字段并不多,大部分都是为了避免回表而添加的额外字段,不需要排序。于是,PG数据库中出现了一种覆盖索引。覆盖索引是PostgreSQL11中引入的新索引。这是一个特殊的复合索引,允许在索引中存储额外的非索引字段。例如:selectcol1fromtab1wherecol2=3;在没有覆盖索引之前,我们需要创建一个(col2,col1)的复合索引,这样这条SQL使用IndexOnlyScan来提高执行效率,减少对表的访问。覆盖索引出现后,就可以创建(col2)include(col1)的索引了。不同于传统的复合索引,额外的字段不需要参与B-TREE的构建,使得索引更加高效。事实上,在复杂的应用场景中,PG提供的索引类型可能无法覆盖一些特殊场景。但是不要害怕,PG提供了一种非常简单的方法,可以让你扩展自己的索引类型来解决应用程序中棘手的性能问题。只要你能想到,索引就是一种额外的数据结构,可以让你更快地找到你需要的数据。你可以使用标准的、通用的B树、位图等结构,也可以使用只有你的应用程序才能理解的数据结构来找到你需要的数据,所以如果你使用的是PG数据库,那你就幸运了,你可以自己定义一个新的索引来适应你的应用。可能在我写这篇文章的时候,其他一些数据库也有这个能力。如果是这样,那么你是对的。索引就是这样,索引并不是你平时理解的死板的数据结构。并不是说你的应用一定适合B树索引,索引也可以适合你的应用。希望我们国内基于PG开源代码开发的数据库一定要保留这个接口,有时候真的可以救命啊。
