【问题标题】:Postgresql - Multiple Indexes with the Same ColumnsPostgresql - 具有相同列的多个索引
【发布时间】:2017-09-08 19:34:57
【问题描述】:
假设我
- 有一个包含 a、b、c 和 d 列的表
- 希望包含这些列组合的 SELECT 查询速度极快
- 希望 a 出现在每个查询中
- 不要关心缓慢的更新和插入
我应该创建哪些索引,并且以不同的顺序创建具有相同列的多个索引是一个可怕的想法?
(a, b)
(a, c)
(a, b, c)
(a, c, b)
...
(a, b, c, d)
(a, d, c, b)
...
【问题讨论】:
-
-
-
Postgres 可以为单个查询组合同一张表上的多个索引。所以我会为每一列尝试一个索引,看看你使用的通常查询的效率如何。如果a 列上的条件已经充分减少了结果中的行数,则所有列上的单个 B 树也可能就足够了。您可能还想在所有列上尝试 BRIN index 或 bloom filter index
标签:
database
postgresql
indices
postgresql-9.5
【解决方案1】:
这个问题目前的形式是无法回答的。影响索引选择和有用性的因素包括:
- 列中数据的基数
- 表中数据的大小
- 数据类型
- 索引的新鲜度
- 查询调优参数
- 是的,索引中列的顺序
话虽如此,了解您的索引将如何执行的唯一方法是使用代表性数据进行测试。
抱歉,这里没有捷径。
【解决方案2】:
理论上,如果您完全不关心更新/插入速度和过多的索引大小(磁盘空间),那么您将需要查询的WHERE 子句中使用的所有可能的列组合,并且查询计划器将决定使用哪一个。但是索引是否有用取决于表数据。
索引列的顺序起着非常重要的作用。列应按基数排序。我们来看例子:
我们有一张人员表(id、surname、firstname、year_of_birth、sex)。
这里适合什么索引?
- 按名称过滤
我们应该添加哪个索引 - (surname, firstname) 或 (firstname, surname)?正确答案是 (surname, firstname),因为如果按姓氏对记录进行分组,记录数肯定会更高。
- 按姓名和出生年份过滤
假设我们已经有 (surname, firstname) 索引。
我们应该将其更改为(姓、名、年)吗?可能会有一些好处,但我对此表示怀疑。对于任何给定的姓氏和名字,可能只有几条不同年龄的记录。关键是,如果我们有几乎唯一的组合(例如姓氏 + 名字),那么向索引添加更多列将无济于事。
- 按性别过滤
不需要索引。因为只有两个可能的值:男/女。所以索引不会有效率。
除了索引非常重要和重要之外,我还想说明几点:
- 索引占用额外的磁盘空间
- 索引会影响更新/插入速度
- 并非所有索引都高效(对于一小部分记录,顺序扫描更快,因为索引查找在性能方面并不是免费的)
- 最终,要使用哪个索引是由查询计划器决定的,这取决于很多因素。有时即使您有索引,它也可能更喜欢顺序扫描。因此,除非您对其进行测试,否则您永远不会知道。
文档中的一个要点:Combining Multiple Indexes
在除最简单的应用程序之外的所有应用程序中,都有可能有用的各种索引组合,数据库开发人员必须做出权衡来决定提供哪些索引。有时多列索引是最好的,但有时最好创建单独的索引并依赖索引组合功能。