问题
Not sure if this is possible in PostgreSQL 9.3+, but I'd like to create a unique index on a non-unique column. For a table like:
CREATE TABLE data (
id SERIAL
, day DATE
, val NUMERIC
);
CREATE INDEX data_day_val_idx ON data (day, val);
I'd like to be able to [quickly] query only the distinct days. I know I can use data_day_val_idx
to help perform the distinct search, but it seems this adds extra overhead if the number of distinct values is substantially less than the number of rows in the index covers. In my case, about 1 in 30 days is distinct.
Is my only option to create a relational table to only track the unique entries? Thinking:
CREATE TABLE days (
day DATE PRIMARY KEY
);
And update this with a trigger every time we insert into data.
回答1:
An index can only index actual rows, not aggregated rows. So, yes, as far as the desired index goes, creating a table with unique values like you mentioned is your only option. Enforce referential integrity with a foreign key constraint from data.day
to days.day
. This might also be best for performance, depending on the complete situation.
However, since this seems to be about performance, there is an alternative solution: you can use a recursive CTE to emulate a loose index scan:
WITH RECURSIVE cte AS (
(SELECT day FROM data ORDER BY 1 LIMIT 1)
UNION ALL
SELECT (SELECT day FROM data WHERE day > c.day ORDER BY 1 LIMIT 1)
FROM cte c
)
SELECT day FROM cte;
This only needs a plain index on day
.
There are various variants, depending on your actual queries. Details:
- Optimize GROUP BY query to retrieve latest record per user
- Unused index in range of dates query
- Select first row in each GROUP BY group?
来源:https://stackoverflow.com/questions/29171623/create-a-unique-index-on-a-non-unique-column