【问题标题】:What is the right way to index a postgres table when doing a query with two fields?使用两个字段进行查询时,索引 postgres 表的正确方法是什么?
【发布时间】:2014-10-23 20:53:57
【问题描述】:

如果我有一张大桌子:

varchar foo
integer foo_id
integer other_id
varchar other_field

我可能会做如下查询:

select * from table where other_id=x

显然我需要在 other_id 上建立索引以避免表扫描。

如果我也在做:

select * from table where other_id=x and other_field='y'

我是否要在 other_field 上创建另一个索引,或者如果我从不这样做,那是不是很浪费:

select * from table where other_field='y'

即我只在查询中同时使用 other_field 和 other_id。

两个 [other_id, other_field] 的复合索引会更好吗?或者这会导致第一个简单查询的表扫描?

【问题讨论】:

    标签: database postgresql database-design database-indexes


    【解决方案1】:

    如果您还没有使用这两个,请使用EXPLAIN and EXPLAIN ANALYZE。了解查询计划基础知识后,您将能够非常有效地优化数据库查询。

    现在的问题 - 在不了解价值观的情况下说任何话可能会产生误导。如果对于任何特定的other_id 没有那么多的other_field 值,那么一个简单的索引other_id 就足够了。如果有很多 other_field 值(即数千个),我会考虑制作复合索引。

    我是否要在 other_field 上创建另一个索引,或者如果我从不这样做,那是一种浪费:

    是的,那很可能是浪费空间。 Postgres 是able to combine two indexes,但条件必须恰到好处。

    两个 [other_id, other_field] 的复合索引会更好吗?

    可能会。

    或者这会导致第一个简单查询的表扫描?

    Postgres 只能对第一列使用多列索引(不完全正确 - 检查答案 cmets)。

    基本规则是 - 获取真实数据集,准备您尝试优化的查询。在这些查询上运行 EXPLAIN ANALYZE。尝试重写它们(即加入而不是子选择,反之亦然)并检查性能(EXPLAIN ANALYZE)。尝试在您认为可能有帮助的地方添加索引并检查性能 (EXPLAIN ANALYZE)...如果没有帮助,请不要忘记删除不必要的索引。

    如果您仍然遇到问题并且您的数据集很大(数千万以上),您可能需要重新考虑甚至运行特定的查询。特定任务可能需要不同的方法(例如批处理/异步处理)或不同的技术。

    【讨论】:

    • 谢谢,这帮助很大。当 SO 允许时,我会将此答案标记为最佳。
    • 几乎重写了答案。有一些错误:)。
    • "Postgres 只能对第一列使用多列索引" - 这并不完全正确:stackoverflow.com/q/26503743/330315
    • 有趣,不知道这个。对提到的句子添加了评论。谢谢。
    【解决方案2】:

    如果other_id 具有高度选择性,那么您可能根本不需要other_field 上的索引。如果索引中只有几行与 other_id=x 匹配,则查看每一行以查看它们是否也匹配 other_field=y 可能足够快,不会打扰更多索引。

    如果您确实需要加快查询速度,那么您几乎肯定需要复合索引。 other_field 上的独立索引不太可能有帮助。

    【讨论】:

      【解决方案3】:

      接受的答案并不完全准确 - 如果您需要问题中提到的所有三个查询,那么您实际上需要两个索引。

      让我们看看哪些索引满足查询中的哪个 WHERE 子句:

                                     {other_id} {other_id, other_field} {other_field, other_id} {other_field}
      other_id=x                     yes        yes                     no                      no
      other_id=x and other_field='y' partially  yes                     yes                     partially
      other_field='y'                no         no                      yes                     yes
      

      所以要满足所有 3 个 WHERE 子句,您需要:

      • {other_id} 上的索引和 {other_field, other_id} 上的复合索引
      • 或 {other_field} 上的索引和 {other_id, other_field} 上的复合索引
      • 或 {other_id, other_field} 上的复合索引和 {other_field, other_id} 上的复合索引。1

      根据您的数据分布,您也可以使用 {other_id} 和 {other_field},但您应该在选择该解决方案之前仔细衡量。此外,您可以考虑将 * 替换为一组更窄的字段,然后将 covering 替换为索引,但这是另一个话题......


      1 比其他两个“更胖”的解决方案 - 仅在您有特定的覆盖需求时才考虑。

      【讨论】:

      • 操作说明第三个查询从未使用过。使接受的答案正确
      • @MatBailie Darn,我错过了!谢谢。
      猜你喜欢
      • 2019-09-21
      • 2014-12-17
      • 1970-01-01
      • 2017-06-03
      • 2021-06-06
      • 2011-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多