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.
CREATE TABLE image (
image_id serial PRIMARY KEY
, group_id int NOT NULL
, name text NOT NULL
);
Indexes are the key ingredient for performance. Ideally, you create these two in addition to the primary key:
CREATE INDEX image_name_grp_idx ON image (name, group_id);
CREATE INDEX image_grp_idx ON image (group_id);
The second may not be necessary, depending on data distribution and other details. See:
Update: this becomes unreliable in Postgres 11 or later when Parallel Append
is 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:
SELECT * FROM image WHERE name = 'name105' AND group_id = 10
UNION ALL
SELECT * FROM image WHERE name = 'name105'
UNION ALL
SELECT * FROM image WHERE group_id = 10
LIMIT 1;
fiddle
Old sqlfiddle
LIKE
without wildcard character is equivalent to =
The LIMIT
clause applies to the whole query. Postgres is smart enough not to execute later legs of the UNION ALL
as soon as it has found enough rows to satisfy the LIMIT
. Consequently, for a match in the first SELECT
of the query, the output of EXPLAIN ANALYZE
looks 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 ms
Bold emphasis mine.
Do not add an outer ORDER BY
clause, this would void the effect. Then Postgres would have to consider all rows before returning the top row.
Is there a generic solution for that?
This is the generic solution. Add as many SELECT
statements as you want.
Of course it would come in handy when the search result is sorted by its relevance.
There is only one row in the result with LIMIT 1
. Kind of voids sorting.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With