Variable is strongly typed. If the statement is "safe" SQL Server will only have ONE plan to use/re-use.
DECLARE @ExecStrNVARCHAR (4000),
@MemberNo INT = 1567;
SELECT @ExecStr =
N'SELECT [m].*
FROM [dbo].[member] AS [m]
WHERE [m].[member_no] = CONVERT (INT, '
+ CONVERT (NVARCHAR (10), @MemberNo) + N')';
SELECT @ExecStr;
EXEC (@ExecStr);
GOUsing REPLACE instead of QUOTENAME. QUOTENAME is limited to NVARCHAR (128) for longer strings - you must use REPLACE:
SELECT @ExecStr = N'SELECT [m].*
FROM [dbo].[member] AS [m]
WHERE [m].[lastname] LIKE CONVERT (VARCHAR (15), '''
+ REPLACE (@lastname, '''', '''''')
+ N''')';DEFAULT: 500 + 20% of the table (member = 10K rows) Member's stats will get INVALIDATED at 2,500 rows 20% = 2000 + 500
Or, if trace flag 2371 is turned on, then updates are dynamic (tied to table size). Read this blog post: http://bit.ly/qOAIqs During compilation the variable was deemed "UNKNOWN" (which makes sense, the assignment doesn't happen until runtime/execution)
DECLARE @LastNameVar VARCHAR (15) = 'Tripp';
-- this is the EXACT same data type as the column
SELECT [m].*
FROM [dbo].[member] AS [m]
WHERE [m].[lastname] = @LastNameVar;
GOIf a value is unknown - it cannot be "sniffed" If it cannot be sniffed then SQL Server has to use the "average" number of rows. This comes from the density vector.
No statistics therefore HEURISTICS. Heuristics = internal rules main point - statistics are generally better than heuristics.
Statistics – if they exist or if they can be (auto) created, using:
- The histogram: when the value can be “sniffed” (parameters)
- The density vector: when the value cannot be “sniffed” (variables)
Heuristics – if there are no statistics available and SQL Server cannot auto create them
-
These are internal 'magic' numbers (cannot be changed)
-
They often result in very poor plans (LEAVE AUTO_CREATE_STATISTICS ON)
-
Sometimes this is the only option when better estimations cannot occur (comparison between columns (e.g. col1 > col2))
Statistics have to be reasonably small to be fast/useful They’re just estimates They’re not always guaranteed to be accurate They’re just meant to get us closer to the right value
show statistincs information
EXEC sp_autostats 'dbo.member'- Rows – number of rows in the table at the time the statistics were built
- Rows Sampled – the number of rows that were analyzed to generate the statistic
- Sampling
- Does not directly indicate a problem with statistics
- Could be a problem if your data is heavily skewed
- Is it a problem?
- Using showplantooltip –estimate vs. actual rows
- Sampling
- If query performance is poor AND the actual is significantly OFF from the estimate then you might want to verify the statistics creation (rows v. rows sampled)
- If statistics were based on a sampling and performance is improved after statistics have been updated, then you might want to turn off auto update for this index (using STATISTICS_NORECOMPUTE) and schedule an UPDATE STATISTICS WITH FULLSCAN
- Estimation comes from “sniffing” the value
- Result:estimate comes from HISTOGRAM
- Pro: estimate is usually more accurate
- Pro: that execution gets a plan designed for that value
- Con: If/when this plan is saved –subsequentexecutions are prone to “parameter sniffing problems” (PSP)
- Result:estimate comes from HISTOGRAM
- Value cannot be “sniffed”
- Result: estimate comes from the DENSITY_VECTOR
- Depends: estimate is an “average”
- Depends: the plan generated is designed for the “average” value –not that value
- Pro:If/when this plan is saved –subsequent executions are NOT prone to PSP
- Con:When your data is NOT [relatively] evenly distributed, this plan might not be good for anyone
- Method: ad hoc statement
- Can have literals
- Can be “sniffed” and estimated using the HISTOGRAM
- Can generate an optimal plan
- Can have variables
- Cannot be "sniffed" (they are unknown during optimization/compilation)
- Optimizes based on the average distribution of data (using the DENSITY_VECTOR)
- Can be parameterized and cached but it’s extremely unlikely (only when safe)
- Requires CPU/compilation on every execution
- Method: sp_executesql
- Can generate an optimal plan for the firstexecution
- Saves CPU/compilations costs for subsequent executions
- Can be prone to parameter sniffing problems (PSP)
- When the optimal plan varies (based on the parameters passed) then subsequent executions may suffer by using the plan chosen by the first execution’s parameters
- Method: Dynamic String Execution through EXEC (@string)
- Turns the statement into an ad hoc statement
- It behaves exactly like an ad hoc statement
- Uses an IN clause
- Has more than one table in the FROM clause
- Uses expressions joined by ORin a WHERE clause
- When a SELECT query contains a sub-query
SIMPLE isn't good for everthing, some statements should be cached FORCED isn't good for everything some statements shouldn't be cached. Can use a hybrid approach Ad hoc when it varies sp_executesql when it doesn't The end result - it's often better to keep the database SIMPLE and force only those statements that are stable
- Ad hoc statements
- Simple parameterization –almost all statements will be compiled just for that execution; they will not be parameterized/saved (see rules for parameterization in whitepaper)
- Forced parameterization –most statements will be parameterized/saved (you’ll see this in decreased CPU/compilations and potential for parameter-sniffing problems)
- sp_executesql (or, prepared statements)
- A fantastic way to reduce the CPU/cache overhead that ad hoc has, but should only be used when a plan is stable and consistent
- This is a better way to force a statement into cache as opposed to using forced parameterization database-wide
- Stored procedures
- Can be “sniffed” but there are exceptions to what SQL Server will store in their plans
| Memory (GB) | Plan Cache (GB) |
|---|---|
| 4 | 3 |
| 8 | 3.5 |
| 16 | 4.2 |
| 32 | 5.8 |
| 64 | 9 |
| 128 | 12.2 |
| 256 | 30 |
On first execution, only the query_hash will go into cache, On second execution (if), the plan will be placed in cache. Create a single and more consistent plan with covering indexes – might make the plans more stable! SQL Server will pick up SOME stable statements IF and ONLY IF they’re SAFE Note: this only reduces compilation costs (e.g. CPU) but it does not reduce plan cache pollution because every ad hoc statement still goes into the ad hoc cache If you create a bunch of stable plans that SQL doesn’t see as SAFE but they essentially are (one query_plan_hashfor each query_hash) then you can consider the database setting: forced parameterization If you’re finding A LOT of single-use statements that have the same query_hashand are executed frequently but with only one query_plan_hashthen this is ideal! But, remember, ad hoc statements are always placed in the ad hoc plan cache so you still need optimize for ad hoc workloads…set that FIRST!
- If SQL Server defines the statement as "safe":
- Nothing do to here as SQL Server parameterizes it
- Better to use sp_executesql to directly reduce ad hoc plan cache pollution
- If you stabilize plans with better indexes, SQL Server might pick up more (of the simple) statements as "safe"
- For ad hoc statements, nothing to do** unless the database is set to FORCED**, if so:
- Change the code – do not use an ad hoc statement, use sp_executesql and OPTION (RECOMPILE)
- If you can’t change the code – use a plan guide template to recompile the plan (PARAMETERIZATION SIMPLE)
- NOTE: If you turn on the server setting: optimize for ad hoc workloads as well as the database option for parameterization: FORCED and you don’t have a lot of executions you can create more plan cache pollution by placing the forced plan at first execution as well as the compiled plan stub
- If SQL Server defines the statement as "unsafe", but the parameters do not require a plan change (i.e. a stable plan):
- Covering indexes often lead to better plan stability…
- If you can change the code –use sp_executesql
- If you can’t change the code –consider a plan guide template to force the plan (PARAMETERIZATION FORCED)
- NOTE: Not all statements can be used in a plan guide template (for example, LIKE) even if the parameters are consistent enough to generate the same plan.
- Generally, avoid changing the database setting for PARAMETERIZATION unless the large majority of statements over your business cycle are stable plans with large numbers of executions (test, test, test!)
- If SQL Server defines the statement as "unsafe" and the parameters supplied require plan changes (i.e. unstable plan):
- Do not use sp_executesql, leave it as ad hoc
- Or, if using sp_executesql–consider adding OPTION (RECOMPILE)
- NOTE: There are other methods for dealing with various PSP patterns but they’re a bit beyond the scope of this course.

Mostly from https://app.pluralsight.com/library/courses/sqlserver-optimizing-adhoc-statement-performance/table-of-contents