Search code examples
sqlpostgresqlquery-performance

PostgresSQL: Performance of using CASE inside WHERE


With PostgreSQL, I needed to define a query that would conditionally SELECT some data based on a parameter. In this statement, I have a condition that only needs to be evaluated only if another condition evaluates to TRUE.

To solve this, my first idea was to use a CASE inside a WHERE, which worked fine. For example, using a table test_table with columns id, name, and value:

SELECT 
    name
FROM test_table
WHERE
    CASE
        WHEN $1 > 10 THEN test_table.value > $1
        ELSE TRUE
    END
;

However, other peers suggested to use regular boolean logic instead, as it would perform faster. For example:

SELECT 
    name
FROM test_table
WHERE
    (
        $1 <= 10
        OR test_table.value > $1
    )
;

After testing with around 100k rows and using EXPLAIN ANALYSE, the speed difference seemed to average at about 1ms difference:

  • With CASE: ~19.5ms Execution Time
  • With Regular Booleans: ~18.5ms Execution Time

Question is: Is the second approach really faster? Or was my testing flawed, and thus the results incorrect?


Solution

  • It is not so much that not using the case is faster all the time. The issue is that case prevents the optimizer from choosing different execution paths. It basically says that the conditions have to be executed in order, because case expressions impose ordering.

    With fewer options, the resulting query plan might be slower.

    There are some cases where the execution order is an advantage. This is particularly true when you know that some condition is very expensive to evaluate, so you want to be sure that other conditions are evaluated first:

    where (case when x = 1 then true
                when <some expensive function> then true
           end)
    

    could be more performant than:

    where (x = 1) or <some expensive function>
    

    (although in this simple example I would expect the Postgres compiler to be smart enough to do the right thing in the second case).

    The second reason for avoiding case in a where clause is aesthetic. There are already sufficient boolean operators to generate just about any condition you need -- so case is syntactic sugar that usually provides no additional nutrients