Branching
Reputation = 2 returns few records while 1 returns a ton
Reputation = 1 wasted 5gb of RAM (25% of server RAM), but doesn't show a yellow bang whereas Reputation = 2 does even though it only wastes a couple MBs
When you cache for the large and run for the small, the small query runs fast, but consumes a lot of cores going parallel and most importantly 5gb of memory
When you cache it the other way around, the small query runs fine, but the large one takes forever because it doesn't go parallel, it does key lookups, and it doesn't have enough memory
This indicates that there is no one single plan that will solve this probem
Branching with IF statement does not work
Dynamic SQL
The above still gets sniffed because the text is the same
In order to fix this, we can use comment injection to change the text of the query
Not shown below, but it is best to put the comment at the beginning of the query because otherwise SQL will not show it in the plan cache as it truncates all comments AFTER a query is finished executing
In the above code, adding IF @Reputation = 1 adds technical debt
Traffic Cop is another solution to achieve branching that allows you to have 2 separate procs with the exact same code, but each proc has their own execution plan
In order to try and find big/small data, you can run a COUNT(*) on the primary table to see how many records might be returned, but the issue with this approach is that you are counting from a table every single time
To get around this, you can use a temp table on the inner proc that is generated from the outer proc so that you aren't doing unnecessary work
Not shown below, but you could also put @@ROWCOUNT below the INSERT INTO #MatchingUsers to avoid the SELECT COUNT(*)
What to take away from this demo:
All of the code in a batch gets compiled at once initially.
If you want a different plan, you have to:
Ask for it - like with a RECOMPILE hint
Change a lot of data, forcing stats to update
Postpone compilation for part of the query: (like build a child stored procedure or dynamic SQL)
Comment injection can be super powerful and low maintenance
But when you do any of the above, you're building technical debt: if the data distribution changes over time, you may need to revisit the triggers you used to spawn the branching logic.
Last updated