Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Postgresql COALESCE performance problem

I have this table in Postgresql:

CREATE TABLE my_table
(
    id bigint NOT NULL,
    value bigint,
    CONSTRAINT my_table_pkey PRIMARY KEY (id)
);

There are ~50000 rows in my_table.

The question is, why the query:

SELECT * FROM my_table WHERE id = COALESCE(null, id) and value = ?

is slower than this one:

SELECT * FROM my_table WHERE value = ?

Is there any solution, other than optimizing the query string in app-layer?

EDIT: Practically, the question is how to rewrite the query select * from my_table where id=coalesce(?, id) and value=? to have worst case performance not less than that of select * from my_table where value=? in Postgresql 9.0

like image 620
Tair Avatar asked Jun 21 '11 13:06

Tair


People also ask

Does coalesce improve performance?

In the case of coalesce, each input partition is included in exactly one output partition. This causes massive performance improvements in the case of coalesce, when you're decreasing the number of partitions.

Is coalesce faster than Isnull?

In a narrow case, using the built-in isnull function results in better performance than coalesce on columns that are not nullable. This pattern should generally be avoided, of course. On columns that are nullable, things can really go sideways in either case.

Which is faster coalesce or case?

COALESCE() is literally shorthand for a CASE statement, they will perform identically. However, as podiluska mentioned, ISNULL() can be occasionally faster than a CASE statement, but it's likely to be a miniscule increase as these functions are very unlikely to bottleneck your procedure.

Is coalesce slow SQL?

SQL COALESCE() Very Cool, But Slower Than ISNULL() The ISNULL() method performed on average at about 550 ms. The COALESCE() method performed on average at about 1500 ms.


1 Answers

Try rewriting the query of the form

SELECT *
  FROM my_table
 WHERE value = ?
   AND (? IS NULL OR id = ?)

From my own quick tests

INSERT INTO my_table select generate_series(1,50000),1;
UPDATE my_table SET value = id%17;

CREATE INDEX val_idx ON my_table(value);

VACUUM ANALYZE my_table;

\set idval 17
\set pval   0

explain analyze 
SELECT *
  FROM my_table
 WHERE value = :pval
   AND (:idval IS NULL OR id = :idval);

Index Scan using my_table_pkey on my_table  (cost=0.00..8.29 rows=1 width=16) (actual time=0.034..0.035 rows=1 loops=1)
   Index Cond: (id = 17)
   Filter: (value = 0)
 Total runtime: 0.064 ms

\set idval null

explain analyze 
SELECT *
  FROM my_table
 WHERE value = :pval
   AND (:idval IS NULL OR id = :idval);

Bitmap Heap Scan on my_table  (cost=58.59..635.62 rows=2882 width=16) (actual time=0.373..1.594 rows=2941 loops=1)
   Recheck Cond: (value = 0)
   ->  Bitmap Index Scan on validx  (cost=0.00..57.87 rows=2882 width=0) (actual time=0.324..0.324 rows=2941 loops=1)
         Index Cond: (value = 0)
 Total runtime: 1.811 ms
like image 57
Gavin Avatar answered Sep 25 '22 02:09

Gavin