1

I'm working on a SQL query where the filters can be dynamic, and I'm concerned about its efficiency. My current approach is as follows:

SELECT *
FROM table t
WHERE (:param1 IS NULL OR t.example = :param1)
  AND (:param2 IS NULL
    OR EXISTS (
        SELECT 1
        FROM other_table o
        WHERE o.id = t.other_id
          AND o.test = :param2
    )
);

My main concern is whether this query, particularly the EXISTS clause, could negatively impact performance.

Should I prefer dynamic sql over this kind of queries?

3
  • Please show the full table and index defintions, and the EXPLAIN plan. Dynamic SQL is usually better for this type of query. Commented Jun 21, 2024 at 18:40
  • actually this is a more general question should I prefer dynamic sql over this? Commented Jun 21, 2024 at 19:02
  • 2
    If you are concerned about performance and database resource usage, use Dynamic SQL. The app will produce a minimal query, instead of a convoluted one that is more difficult to optimize. Commented Jun 22, 2024 at 4:04

1 Answer 1

3

To get optimized query plans, dynamic SQL is typically superior, especially when queries get more complex.

For instance, if you prepare your generic query like this:

PREPARE q1 (int, text) AS
SELECT *
FROM   tbl t
WHERE (:param1 IS NULL OR t.example = :param1)  -- simple
AND   (:param2 IS NULL OR EXISTS (              -- more complex
   SELECT FROM other_table o
   WHERE  o.id = t.other_id
   AND    o.test = :param2
   ));

Then the simple case may still result in the best query plan:

EXECUTE q1(123, null);

Postgres is able to prune parts of the query plan that are obviously redundant, even when executing a prepared statement. So the whole EXISTS branch does not enter into the query plan in this case. And Postgres tries to be smart about using a generic plan or not. Read details in the manual. But your generic query also adds noise in the form of all these ugly OR's. And that has an impact, too.

Dynamic SQL would execute:

SELECT *
FROM   tbl t
WHERE  t.example = 123;

But more complex cases are more likely to get a sub-optimal plan:

EXECUTE q1(null, 'foo');

Postgres still prunes the obviously redundant part, but may use a generic plan, where it might optimize better based on constant input, and without the added OR.
Dynamic SQL typically produces a better query plan:

SELECT *
FROM   tbl t
WHERE  EXISTS (
   SELECT FROM other_table o
   WHERE  o.id = t.other_id
   AND    o.test = 'foo'
   ));

On the other hand, if a single generic query simplifies query generation, and if performance is not important (because it's fast either way), or if the generic query plan happens to turn out just right, it may still be sensible. Big IF's.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.