You are right to worry about the execution plan being cached.
Martin gives a good example showing that the plan is cached and will be optimized for a specific branch of your logic on first run. After the first execution, this plan is reused, even if you call the stored procedure (sproc) with another parameter, as a result of which the executable thread selects another branch. This is very bad and will kill performance. I have seen this happen many times, and it takes some time to find the root cause.
The reason for this is called the โForced parameterโ , and it is worth exploring.
The general suggested solution (which I do not recommend) is to split your sproc into several tiny ones. If you call sproc inside sproc, then internal sproc will get an execution plan optimized for the passed parameter.
Splitting sproc into several smaller ones when there is no good reason (modularity is a good reason) is an ugly workaround. Martin shows that you can recompile the instruction by introducing a circuit change. I would use OPTION (RECOMPILE) at the end of the statement. This instructs the optimizer to recompile taking into account the current value of all variables: not only the parameters are taken into account, but also local variables, which can distinguish between a good and a bad plan.
Let's get back to your question about building a query with another where clause according to the parameter. I would use the following template:
WHERE (@parameter1 is null or col1 = @parameter1 ) AND (@parameter2 is null or col2 = @parameter2 ) ... OPTION (RECOMPILE)
The downside is that the execution plan for this statement is never cached (it does not affect caching to the point of the statement, though), which can have an effect if sproc is executed many times, since the compilation time should now be taken into account. Performing a test with product quality data will give you an answer if this is a problem or not.
On the plus side, you can code readable and elegant sprocs without having to set the optimizer on the wrong foot.
Another possibility to keep in mind is that you can disable execution plan caching at the sproc level (as opposed to the instruction level), which is less granular and, more importantly, will not take into account the value of local variables when optimizing.
Additional information at http://www.sommarskog.se/dyn-search-2005.html http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/