Search code examples
postgresqlcoalescenull-coalescing

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


Solution

  • 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