在使用两个字段进行查询时索引postgres表的正确方法是什么?

时间:2014-10-23 20:53:57

标签: database postgresql database-design database-indexes

如果我有一张大表:

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]的复合索引会更好吗?或者这会导致第一次简单查询的表扫描?

3 个答案:

答案 0 :(得分:2)

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

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

  

我是否希望在other_field上使用其他索引,或者如果我从未这样做,那就是浪费:

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

  

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

可能会。

  

或者是否会导致第一次简单查询的表扫描?

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

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

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

答案 1 :(得分:0)

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

如果事实证明您确实需要更快地进行查询,那么您几乎肯定需要复合索引。 other_field上的独立索引不太可能有所帮助。

答案 2 :(得分:0)

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

让我们看看哪些索引满足查询中的哪个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 " Fatter"解决方案比其他两个 - 只考虑您是否有特定的覆盖需求。