Dynamic SQL: How to Build Fast Multi-Parameter Stored Procedures
- 2. About me
1999-05: dev, architect, DBA
2005-08: DBA, VM/SAN admin
2008-10: MCM, Quest Software
Ever since: consulting DBA
BrentOzar.com/go/dynamicsql
- 3. Agenda
What we’re trying to do
A few ways we shouldn’t do it, and why
The “right” way: sp_executesql
The drawbacks of the right way
Pro tips: troubleshooting and tuning
- 5. Q&A site: you ask, other people do your job
Whole database is available under Creative Commons
Download it free: BrentOzar.com/go/querystack
We’ll use the dbo.Users table
- 6. How big is our Users table today?
Stored proc in your resources
StackOverflow2010
- 8. Our proc has to look like this:
CREATE OR ALTER PROC dbo.usp_SearchUsers
@SearchDisplayName NVARCHAR(100) = NULL,
@SearchLocation NVARCHAR(100) = NULL,
@SearchReputation INT = NULL…
And folks want to pass in 1, 2, or 3 parameters, like just
DisplayName, OR
both Location and Reputation, and filter both.
- 9. But we wanna do less reads, so…
CREATE INDEX IX_DisplayName
ON dbo.Users(DisplayName);
CREATE INDEX IX_Location
ON dbo.Users(Location);
CREATE INDEX IX_Reputation
ON dbo.Users(Reputation);
- 13. At first glance, it works.
Granted, the results aren’t accurate,
but it is willing to use indexes.
But there’s a catch.
- 19. We’re hitting parameter sniffing.
SQL Server compiles the entire plan
the first time it runs,
using the parameter values it was first run with.
So it’s optimizing the @SearchLocation branch with a null
@SearchLocation value.
- 20. This design has 3 big problems.
1. It produces the wrong results for param combos.
2. It’s a little TOO willing to use indexes,
even when they’re worse than a table scan.
3. It underestimates memory grants.
- 38. We bloat the plan cache a little.
The proc has its own entry, executed 6 times.
Each dynamic SQL string gets its own line.
But each dynamic plan is great* for that set of parameters!
* Not necessarily.
- 39. I got 99 problems plans
Each dynamic SQL plan has its own:
• Plan cache entry
• Memory grant
• Row estimations
• Parameter sniffing issues
- 40. Yes, I can still have param sniffing.
Chicago: big, but not huge.
London: big enough that a scan makes more sense.
- 41. If Chicago runs first…
We cache a plan with a seek.
And reuse it for London.
- 42. If London runs first…
We cache a plan with a scan.
And reuse it for Chicago
But the memory grant is too big.
- 43. Dynamic SQL
Gives you the luxury of multiple plans,
one for each set of parameters
But curses you with multiple plans,
each of which may have parameter sniffing issues.
- 44. There’s much more to learn.
Your demo scripts continue with pro tips for:
• Using comments inside the dynamic SQL string itself
for tracking down the source
• Formatting the strings with CR/LR
• Using debug variables to print at strategic times
• The perils of dynamic sorting
Download: BrentOzar.com/go/dynamicsql