1

If I have a large table with:

varchar foo
integer foo_id
integer other_id
varchar other_field

And I might be doing queries like:

select * from table where other_id=x

obviously I need an index on other_id to avoid a table scan.

If I'm also doing:

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

Do I want another index on other_field or is that a waste if I never do:

select * from table where other_field='y'

i.e. I only use other_field with other_id together in a query.

Would a compound index of both [other_id, other_field] be better? Or would that cause a table scan for the 1st simple query?

Andrew Arrow
  • 4,248
  • 9
  • 53
  • 80

3 Answers3

2

Use EXPLAIN and EXPLAIN ANALYZE, if you are not using these two already. Once you understand query plan basics you'll be able to optimize database queries pretty effectively.

Now to the question - saying anything without knowing a bit about the values might be misleading. If there are not that many other_field values for any specific other_id, then a simple index other_id would be enough. If there are many other_field values (i.e. thousands), I would consider making the compound index.

Do I want another index on other_field or is that a waste if I never do:

Yes, that would be very probably waste of space. Postgres is able to combine two indexes, but the conditions must be just right for that.

Would a compound index of both [other_id, other_field] be better?

Might be.

Or would that cause a table scan for the 1st simple query?

Postgres is able to use multi-column index only for the first column (not exactly true - check answer comments).

The basic rule is - get a real data set, prepare queries you are trying to optimize. Run EXPLAIN ANALYZE on those queries. Try to rewrite them (i.e. joins instead of subselects or vice versa) and check the performance (EXPLAIN ANALYZE). Try to add indexes where you feel it might help and check the performance (EXPLAIN ANALYZE)... if it does not help, don't forget to drop the unnecessary index.

And if you are still having problems and your data set is big (tens of millions+), you might need to reconsider even running specific queries. A different approach might be needed (e.g. batch / async processing) or a different technology for the specific task.

Pavel Horal
  • 17,782
  • 3
  • 65
  • 89
0

If other_id is highly selective, then you might not need an index on other_field at all. If only a few rows match other_id=x in the index, looking at each of them to see if they also match other_field=y might be fast enough to not bother with more indexes.

If it turns out that you do need to make the query faster, then you almost surely want the compound index. The stand alone index on other_field is unlikely to help.

jjanes
  • 37,812
  • 5
  • 27
  • 34
0

The accepted answer is not entirely accurate - if you need all three queries mentioned in your question, then you'll actually need two indexes.

Let's see which indexes satisfy which WHERE clause in your queries:

                               {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

So to satisfy all 3 WHERE clauses, you'll need:

  • either an index on {other_id} and a composite index on {other_field, other_id}
  • or an index on {other_field} and a composite index on {other_id, other_field}
  • or a composite index on {other_id, other_field} and a composite index on {other_field, other_id}.1

Depending on distribution of your data, you could also get away with {other_id} and {other_field}, but you should measure carefully before opting for that solution. Also, you may consider replacing * with a narrower set of fields and then covering them by indexes, but that's a whole other topic...


1 "Fatter" solution than the other two - consider only if you have specific covering needs.

Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167