To use indexes for all possible equality conditions on N
columns, you will need C([N/2], N)
indexes, that is N! / ([N/2]! * (N - [N/2])!)
See this article in my blog for detailed explanations:
You can also read the strict mathematical proof by Russian mathematician Egor Timoshenko
(update: now in English).
One can, however, get decent performance with less indexes using the following techniques:
Index merging
If the columns col1
, col2
and col3
are selective, then this query
SELECT *
FROM mytable
WHERE col1 = :value1
AND col2 = :value2
AND col3 = :value3
can use three separate indexes on col1
, col2
and col3
, select the ROWID
's that match each condition separately and them find their intersection, like in:
SELECT *
FROM (
SELECT rowid
FROM mytable
WHERE col1 = :value1
INTERSECT
SELECT rowid
FROM mytable
WHERE col2 = :value2
INTERSECT
SELECT rowid
FROM mytable
WHERE col3 = :value3
) mo
JOIN mytable mi
ON mi.rowid = mo.rowid
Bitmap indexing
PostgreSQL
can build temporary bitmap indexes in memory right during the query.
A bitmap index is quite a compact contiguous bit array.
Each bit set for the the array tells that the corresponging tid
should be selected from the table.
Such an index can take but 128M
of temporary storage for a table with 1G
rows.
The following query:
SELECT *
FROM mytable
WHERE col1 = :value1
AND col2 = :value2
AND col3 = :value3
will first allocate a zero-filled bitmap large enough to cover all possible tid
's in the table (that is large enough to take all tid
's from (0, 0)
to the last tid, not taking missing tid
's into account).
Then it will seek the first index, setting the bits to 1
if they satisfy the first condition.
Then it will scan the second index, AND
'ing the bits that satisfy the second condition with a 1
. This will leave 1
only for those bits that satisfy both conditions.
Same for the third index.
Finally, it will just select rows with the tid
's corresponding to the bits set.
The tid
's will be fetched sequentially, so it's very efficient.