What if I want to search for a single row in a table with a decrementing precision, e.g. like this:
SELECT * FROM image WHERE name LIKE 'text' AND group_id = 10 LIMIT 1
When this gives me no result, try this one:
SELECT * FROM image WHERE name LIKE 'text' LIMIT 1
And when this gives me no result, try this one:
SELECT * FROM image WHERE group_id = 10 LIMIT 1
Is it possible to do that with just one expression?
Also there arises a problem when I have not two but e.g. three or more search parameters. Is there a generic solution for that? Of course it would come in handy when the search result is sorted by its relevance.
Test setup
Indexes are the key ingredient for performance. Ideally, you create these two in addition to the primary key:
The second may not be necessary, depending on data distribution and other details. See:
Query
Update: this becomes unreliable in Postgres 11 or later when
Parallel Appendis used for big sets! Consider this question and answers (incl. a reliable alternative in my answer):This should be the fastest possible query for your case:
fiddle
Old sqlfiddle
LIKEwithout wildcard character is equivalent to=The
LIMITclause applies to the whole query. Postgres is smart enough not to execute later legs of theUNION ALLas soon as it has found enough rows to satisfy theLIMIT. Consequently, for a match in the firstSELECTof the query, the output ofEXPLAIN ANALYZElooks like this (scroll to the right!):Limit (cost=0.00..0.86 rows=1 width=40) (actual time=0.045..0.046 rows=1 loops=1) Buffers: local hit=4 -> Result (cost=0.00..866.59 rows=1002 width=40) (actual time=0.042..0.042 rows=1 loops=1) Buffers: local hit=4 -> Append (cost=0.00..866.59 rows=1002 width=40) (actual time=0.039..0.039 rows=1 loops=1) Buffers: local hit=4 -> Index Scan using image_name_grp_idx on image (cost=0.00..3.76 rows=2 width=40) (actual time=0.035..0.035 rows=1 loops=1) Index Cond: ((name = 'name105'::text) AND (group_id = 10)) Buffers: local hit=4 -> Index Scan using image_name_grp_idx on image (cost=0.00..406.36 rows=500 width=40) (never executed) Index Cond: (name = 'name105'::text) -> Index Scan using image_grp_idx on image (cost=0.00..406.36 rows=500 width=40) (never executed) Index Cond: (group_id = 10) Total runtime: 0.087 msBold emphasis mine.
Do not add an outer
ORDER BYclause, this would void the effect. Then Postgres would have to consider all rows before returning the top row.Final questions
This is the generic solution. Add as many
SELECTstatements as you want.There is only one row in the result with
LIMIT 1. Kind of voids sorting.