I'm refactoring a health monitoring system which requires that certain attributes of an Entity have to be unique across the system. The attributes of an Entity are configurable by the end-user and the user can pick one or more attributes to be unique (either "universally" unique or unique across a geographical area).
Currently, the solution performs very poorly when looking up these unique values (we use Postgres). By using Postgres partial indexes mitigates the performance issue,but, on large datasets (500 millions rows, which is not unusual) the performance is not acceptable.
One solution I'm considering is to hash the attribute + value using a trigger before INSERT and UPDATE. The trigger would check this "hashes" unique-index before allowing the INSERT. If the hash is missing, then it inserts. Otherwise it blocks the operation.
Is there a better solution to this problem, considering the size of the dataset?
Edit:
Following @JimmyJames suggestion (use a Bloom index), I did run some tests to verify which index is faster for a direct lookup. Env: Postgres 12, 64Gb ram, 16 cores AMD
First I have created 500 millions pseudo-hashes:
insert into bloom_filter (
hash
)
select
gen_random_uuid()
from generate_series(1, 500000000) s(i);
Created a b-tree index:
CREATE INDEX idx_btree_bar on bloom_filter (hash);
Index creation took ~19 min.
A simple lookup takes 24ms. (milliseconds)
select count(*) from bloom_filter where hash= '99c2b46f-cc36-4249-ae36-f16f047f2962';
Then, I have killed the b-tree index, and created a bloom index:
CREATE EXTENSION bloom;
CREATE INDEX idx_bloom_hash ON bloom_filter USING bloom(hash)
WITH (length=64, col1=4);
Index creation took: 2m 54s
Same lookup query as above takes 1.536 sec., which is significantly more than a b-tree index.
Not surprisingly, an hash
index has a similar look-up speed of a b-tree index.