Multiple Execution Paths
It’s not uncommon to find stored procedures that have multiple IF statements controlling the flow of execution within the procedure. Now this seems to be a fairly logical thing to do, but there can be a subtle performance problem with this, one that may be hard to identify.
Let’s have a look at a simple example (using AdventureWorks)
CREATE PROCEDURE MultipleExecPaths ( @TransactionType char(1) = NULL ) AS IF @TransactionType IS NULL SELECT max(transactionDate) from Production.TransactionHistory ELSE SELECT max(transactionDate) from Production.TransactionHistory WHERE TransactionType = @TransactionType GO
Nice and simple. If the parameter is passed, get the latest date for that transaction type, if the parameter is not passed, ie is null, get the latest date over all transaction types. So what’s wrong with this?
The problem goes back to parameter sniffing. When the procedure is first executed the first time all queries in the procedure are parsed, bound and optimised. When the optimiser processes each statement to generate an execution plan it uses the values passed for the various parameters to estimate the number of rows affected. The number of rows that the optimiser thinks the queries will process affects the choice of operators for the plan. Operators that are optimal for small numbers of rows are not always optimal for large numbers of rows, and sometimes the difference can be astounding.
Let’s see how the example above plays out to understand what’s happening here.