Pergunta

Consider that I have a table named MYBOOKS consists of over a Million of rows of data. I want to create a stored procedure to return a particular book if :BOOKID is provided, or, return all rows if :BOOKID is 0.

So here's the SQL that I came up with.

SELECT *
FROM MYBOOKS
WHERE :BOOKID = 0 OR BOOKID = :BOOKID

Let's say I want to find :BOOKID = 102. This works, but it actually scans through millions of rows before returning just one row of data that I'm looking for. Is there a way to improve this SQL?

Please note that the illustration above has been simplified. In actual case, I have many more conditions in the WHERE clause and I want to make all of them OPTIONAL too.

SELECT *
FROM MYBOOKS
WHERE (:BOOKID = 0 OR BOOKID = :BOOKID) AND
      (:AUTHORID = 0 OR AUTHORID = :AUTHORID) AND
      (:TITLE = '' OR TITLE = :TITLE)
      //..... and so on

Is it possible to improve this SQL? Thanks.

Foi útil?

Solução

Using conditional WHERE is expensive. Firebird doesn't short circuit these kinds of evaluations and the optimizer is unable to select an optimal plan this way. It is probably better to generate the WHERE condition dynamically.

Other solutions include using a UNION, for example when you replace your first query with:

SELECT *
FROM MYBOOKS
WHERE BOOKID = :BOOKID
UNION ALL
SELECT *
FROM MYBOOKS
WHERE :BOOKID = 0

The optimizer usually chooses a better plan for this query, but given the multiple conditions you want to apply, this probably is not feasible.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top