NAV5SP1 introduces prepared SQL statements to prevent parameter sniffing, but how do I re-create it in a SSMS Query Window?
I have used the T-SQL statement from
http://blogs.msdn.com/microsoft_dynamic ... story.aspx and found several statements with “room for improvements”.
One of the queries seems quite simple:
(@P1 int,@P2 int,@P3 varchar(20))
SELECT * FROM "MyDatabase"."dbo"."MyCompany$Registered Whse_ Activity Line" WITH (READUNCOMMITTED)
WHERE (("Activity Type"=@P1)) AND (("Source Type"=@P2)) AND (("Source No_"=@P3))
ORDER BY "Activity Type","Source Type","Source No_","Registering Date","No_","Line No_"
I had already reduced the indexes of the table a lot, but I have the original primary key marked as Clustered and have an Index purely containing the “Source No_”. All in all I don’t see any reason why this shouldn’t work smoothly. However the statistics say its avg_logical_reads is 11.086.082 !!
The query runs fine when executed in the old fashioned style, but apparently it doesn’t when NAV is using its prepare/execute logic. So how do I re-create the query the-NAV-way, or can someone suggest me what the problem might be? :?:
Thanks in advance
edit: Changed thread subject from "How to re-create a NAV SQL statement (with Prepare/Execute)?" to reflect the latest discussion...
Comments
Indexhint / Recompile is not activated?
Do you have maintenace jobs on the sql server? If yes, which and how often runs these jobs?
Do you know where in NAV this statement is fired?
"Activity Type","Source Type","Source No_","Registering Date","No_","Line No_" is not the Primary key and it's not a default key. So it's a customized key. Which index use the SQL server if this query is executed (Index$0,$1,$2, and so on)?
Also i belave, that this key ("Activity Type","Source Type","Source No_","Registering Date","No_","Line No_") is not very effective for the sql server You filter on the Source No. so, why do doesn't begin you key with this identifer (for your query example where you need all the lines for a specific Source no)?
So it's more effective for the server to find the result set so fast as possible ....
viewtopic.php?f=34&t=32657
Regards
When I execute the statement directly (without prepare/execute) it uses the “Source No_” index as expected, so no problem. But apparently NAV makes it use the clustered primary index instead. That’s why I would like to be able to replicate the way NAV is executing the SQL statement.
I agree that the sort order is not the most optimal, but if SQL just used the proper index it shouldn’t be a problem for it to sort the 5-10 records on-the-fly before presenting it to NAV.
Peter
sp_updatestats
go
sp_createstats 'indexonly' '<- stats only for indexfields should be enough
and a ReBuildIndex maint. job.
Now, it's very helpful to know from where in NAV this query is executed (you can search for it with the DEVTol) and run then this query in NAV (after the jobs are executed). Start also the sql profiler to record the queries (how to setup the sql profiler follow the link above)
Regards
NAV5SP1 introduces a new way to execute SELECT statements to prevent parameter sniffing. How do I do the same in a query window?
Peter
The prepare solution is working briliant at our customers. I cannot remember the last time I created an index hint. We are removing them now...
However, the statement still behaves as expected (9% on the “Source No_” index, 61% on Key Lookup and 30% on sorting). But why does the Execution Plan Cache have information about 13 executions with an average of more than 11 million reads? (And why does it keep reporting only 13 executions, when I have executed it multiple times in a query window??)
And I agree about the Index Hints – I actually expected we needed to hint the indexes starting with Open, but it rarely seems necessary.
Peter
Hope this makes sense...
Could the problem simply be the query from Lars that returns misleading results? (Having read most of Lars’ entries I doubt it, but you never know :-))
Peter
Well, you mentioned you have removed several indexes. Actually this it not necessarily an improvement: you should only remove indexes which are not used - and this you have to KNOW, not just guess ...
There is a difference when executing the "same" TSQL statement via NAV or SSMS: with NAV this is a "cursor operation", with SSMS it isn't; this alone could be reason for getting different Execution Plans, besides any Parameter Sniffing issues.
This huge number of reads actually indicates that the table/clustered index is scanned, so I suggest to add this index: (or implement something similar in NAV) Anything changes?
Something general about the "prepare statements":
actually it works like this: first the SHOWPLAN_ALL is set to ON, so the SQL Server will not process the following query but just generate an execution plan. Then the query is sent - an EP is generated - then SHOWPLAN_ALL is set to OFF.
This gives the SQL Server a chance to generate a good EP, not using an old cached one and doing something stupid.
This preparation solves lot of problems, but not all. In some cases you might still need RECOMPILE hints to really get the best EP ...
NAV/SQL Performance Optimization & Troubleshooting
STRYK System Improvement
The Blog - The Book - The Tool
I know randomly removing indexes isn’t the way to optimize a NAV solution, but I’ll claim I have a bit of knowledge about SQL and the customers NAV usage so I’m quite sure my changes all in all are for the better :-)
(And I would even say, that just because an index is currently used it doesn’t mean it is best to keep it as it is, but that is a different discussion)
Regarding trying to add an index, then I’m simple examining a server that has been used for preliminary test before going live (got 20 users to run extensive test for more than half a day). So I need to extract all the information I can based on the current statistics and the saved traces of long transactions. (And deadlocks, but that is also a different discussion)
Thanks for the information about SHOWPLAN_ALL, but it doesn’t seem to be the way NAV5SP1 is working. I’m quite sure I have seen it demonstrated that first a SELECT statement got prepared and SQL returned some sort of ID of the statement. Next the parameters were set and the statement was executed by referencing to the ID provided from the initial call. But Mark’s suggestion of simply getting the suggested EP seems to give a usable answer.
I tried experimenting executing a cursor operation like this: This just resulted in lot of additional information in the EP, but the usage of indexes seems to be exactly the same as for non-cursor operations. (Isn’t NAV5SP1 using a fast-forward cursor, or has that been changed as well?)
Any other suggestion why the EP seems ok, but the cache statistics seems to be so bad?
Peter
But even though you have "optimized" the indexes - while KNOWING what you were doing - is there any change once you add my proposed index? Have you tried a RECOMPILE hint here?
NAV/SQL Performance Optimization & Troubleshooting
STRYK System Improvement
The Blog - The Book - The Tool
Peter
If that is indeed the case, you could only fix this by providing an optimized index to avoid generating such a bad EP, and/or applying a RECOMPILE hint to give SQL a chance to create a better EP than the cached one (if that still fails I would go for an INDEX hint).
NAV/SQL Performance Optimization & Troubleshooting
STRYK System Improvement
The Blog - The Book - The Tool
More info can be found here:
http://blogs.msdn.com/microsoft_dynamic ... types.aspx
http://blogs.msdn.com/nav_developer/arc ... 0-sp1.aspx
I find this change to have bigger drawbacks than benefits. Any comments? :-k
Peter
--- Edit ---
Ups, sorry, just realized you've mentioned this one ... :oops:
I think with DYNAMIC cursors it's somewhat "trickier" to create really good indexes, to find the fair compromise between WHERE and ORDER BY optimization ... but so far I have not seen too many severe problems caused by this; and if so, usually I could fix it by adding/changing an index ...
NAV/SQL Performance Optimization & Troubleshooting
STRYK System Improvement
The Blog - The Book - The Tool
Take my query as an example:
WHERE (("Activity Type"=@P1)) AND (("Source Type"=@P2)) AND (("Source No_"=@P3))
ORDER BY "Activity Type","Source Type","Source No_","Registering Date","No_","Line No_"
Here SQL picks this index: "Activity Type","Source Type","Registering Date"
Ok, then I tried to change the SQLIndex of this key to simply be "Registering Date".
It still picked this index, eventhough it has an index just with the "Source No." !! ](*,)
I really don't see how this could be better than picking the "Source No." index, and then sort the 5-15 lines afterwards...
Well, then I just have to make the "Activity Type","Source Type","Source No_" index to get SQL happy (but rather stupid IMHO)
Peter
I rest my case... ](*,)
Peter
meanwhile I really agree that the DYNAMIC cursors are a pain ... ](*,)
Previously I could fix most problems by adding somewhat optimized indexes which where a fair compromise between WHERE and ORDER optimization.
But just recently I've been working on a system which REALLY suffers from this cursor stuff ... SQL Server ALWAYS picking the index related to the ORDER BY / Key used ... thus, stupidly scanning indexes (in this case it tool 2.000.000 Reads and 2.500 msec).
After fiddling a lot with this (Indexes, RECOMPILE, etc.), I finally could only fix this by providing an index the contained ALL fields from the WHERE clause plus ALL field from the ORDER BY ... of course, this created supersize indexes, but I could cut down the Reads to 6, Duration to 1 msec ...
But this CANNOT be the general solution for this; I think it would be smart if MS provides us a feature to swith back to FAST_FORWARD cursors ... :-k
NAV/SQL Performance Optimization & Troubleshooting
STRYK System Improvement
The Blog - The Book - The Tool
I was starting to think I was the only one with this problem.
We really need MS to make it optional in some way, or a way to tell SQL to use a better EP for dynamic cursors...
I have been told by MS that dynamic cursors results in fewer locking problems, eventhough they result in more reads. I don't see why this should be the case, but I don't know enough about how SQL handle the different cursor types (except for the poor EP for Dynamic cursors). Do you know anything about that?
Peter
If a "bad" cursors causes an index scan - especially clustered index scan - then this scan has a higher probability of getting blocked (e.g. if another process is writing data into this index) than if performing a straight index seek ...
But this issue should happen in any case - fast forward and dynamic cursors ...
I posted a comment on the related SE BLOG, waiting for reply ...
NAV/SQL Performance Optimization & Troubleshooting
STRYK System Improvement
The Blog - The Book - The Tool
Thanks.
Peter