Dynamic SQL - long execution time - first time only - sql

I have stored procedure which is building dynamic SQL statement depending on its input parameters and then executed it.
One of the queries is causing time outs, so I have decided to check it. The first time (and only the first time) the issue statement is executed it is slow (30 secs - 45 secs) and every next execute takes 1-2 seconds.
In order to reproduce the issue, I am using
DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS
I am really confused where the problem is, because ordinary if SQL statement is slow, it is always slow. Now, it has long execution time only the first time.
Is is possible, the itself to be slow and needs optimization or the problem can be caused by something else?
The execution plan is below, but for me there is nothing strange with it:

From your reply to my comment, it would appear that the first time this query runs it is performing a lot of physical reads or read-ahead reads, meaning that a lot of IO is required to get the right pages into the buffer pool to satisfy this query.
Once pages are read into the buffer pool (memory) they generally stay there so that physical IO is not required to read them again (you can see this is happening as you indicated that the physical reads are converted to logical reads the second time the query is run). Memory is orders of magnitude faster than disk IO, hence the difference in speed for this query.
Looking at the plan, I can just about see that every read operation is being done against the clustered index of the table. As the clustered index contains every column for the row it is potentially fetching more data per row than is actually required for the query.
Unless you are selecting every column from every table, I would suggest that creating non-clustered covering indexes that satisfy this query (that are as narrow as possible), this will reduce the IO requirement for the query and make it less expensive the first time round.
Of course this may not be possible/viable for you to do, in which case you should either just take the hit on the first run and not empty the caches, or rewrite the query itself to be more efficient and perform less reads.

Its very simple the reason 1st and very 1st time it takes longer and then all later executions are done fairly quickly. the reason behind this mystery is "CACHED EXECUTION PLANS".
While working with Stored Procedures, Sql server takes the following
steps.
1) Parse Syntax of command. 2) Translate to Query Tree. 3) Develop
Execution Plan. 4) Execute.
The 1st two steps only take place when you create a Stored Procedure.
3rd step only takes place on very 1st Execution or if the CACHED PLAN has been flushed from the CACHE MEMORY.
Fourth Step takes place on every execution, and this is the only step that takes place after the very 1st execution if the Plan is still in cache memory.
In your case its quite understandable that very 1st execution took long and then later it gets executed fairly quickly.
To reproduce the "issue" you executed DBCC FREEPROCCACHE AND DBCC DROPCLEANBUFFERS commanda which basically Flushes the BUFFER CACHE MEMORY and causes your stored procedure to create a new Execution plan on it next execution. Hope this will clear the fog a little bit :)

Generally, when a Stored procedure is first created, or its statistics etc reset, it will take the first value passed into the Stored Procedure as the 'default' value for the stored procedure. It will then try to optimize itself based off of that.
To stop that from happening, there are a couple of things you can do.
You could potentially use the Query hints feature to mark certain variables as Unknown. So, as an example, at the end of the stored procedure you could put something along the lines of:
select * from foo where foo.bar = #myParam option (optimize for #myParam unknown)
As another approach, you could force the SQL plan to be re-compiled each time - which might be a good idea if your stored procedure is highly variable in the type of SQL it generates. The way you'd do that is:
select * from foo where foo.bar = #myParam option (optimize recompile)
Hope this helps.

Related

Oracle query runs faster when I added some commented out lines

I have a query that runs slow (around 5 minutes), but if I add this commented out lines, it runs very fast (about 2 seconds), which doesn't make sense at all.
What could be the explanation ?
FROM .....
--CREF.SYSTEM_PARAMETER sp,
...
WHERE ....
--t.LEDGER_EFFECTIVE_DATE BETWEEN NVL(adhoc.START_DATE, TRUNC(SYSDATE) - sp.value) and nvl(ec.END_DATE, TRUNC(SYSDATE)) -- use t.LEDGER_EFFECTIVE_DATE
Thank you.
One possibility is that the original query is cached with a poor execution plan, so every time the database sees that query it uses the cached plan. The amended version gets a fresh parse and a new execution plan.
Perhaps if you invalidated the slow version in some way (gather stats with noinvalidate => false, add an empty comment to the table, flush the shared pool, restart the database etc) it would get the new plan.
You mentioned "The explain plan for both are exactly the same" - the explain plan utility shows the plan likely to be used at the next execution. You need to check the actual runtime execution plan, not the explain plan.
Oracle creates a cache when the query is executed multiple times, which can result in reduced execution time. Are you executing the query multiple times?

ALTER stored procedure (with no changes) causes it to run 20x slower

I've been doing some speed tests on a stored procedure that does a bulk insert. It takes some JSON as a parameter, creates a table variable, weeds out any duplicates in the table variable from what's already in the destination table, and then copies the data from the table variable to the destination table.
In running these tests, I was seeing some wildly different speed results that were driving me nuts. They made no sense. I finally pinned down the issue and I'm able to reproduce it consistently.
Here's the process:
Delete all data from the destination table
Run the stored procedure and pass in a JSON record of 50,000 rows
It executes in about 1.5 seconds.
Repeat the process. This time it has existing data it needs to parse looking for duplicates. Same results. Less than 2 seconds
Repeat step 4 N times always with the same results.
Run an ALTER on the SP without having made ANY changes to the SP itself
Repeat step 4. This time it takes 30-40 seconds!!!
Delete the data in the destination table, repeat all the steps, same results.
I've been reading up on parameter sniffing, trying things like converting the passed in parameters to local parameters, and adding WITH RECOMPILE, but so far, the results are all the same.
If this were to happen in prod, it would be unacceptable. Does anyone have any ideas?
Thanks!
This is a bit long for a comment.
SQL Server caches the plans for queries in a stored procedure when they are first run. In your case, the first run has an empty table so the query plan is based on an empty table. That seems to be a good query plan for your problem.
When you alter the stored procedure, you do have one effect: it forgets the cached query plan. So a new plan is generated, one that uses the current size of the table.
For whatever reason, this second query plan is much worse than the first. I don't know why. Usually the problem is the other way around (the query plan on the empty table is the worse one).
I would suggest that you figure out how to get the query to have the right plan when there is data and to recompile the code in the stored procedure each time it is run. That might be overkill, but it adds just a little overhead.

SQL Server stored procedure reducing amount of memory granted

Execution Plan Download Link: https://www.dropbox.com/s/3spvo46541bf6p1/Execution%20plan.xml?dl=0
I'm using SQL Server 2008 R2
I have a pretty complex stored procedure that's requesting way too much memory upon execution. Here's a screenshot of the execution plan:
http://s15.postimg.org/58ycuhyob/image.png
The underlying query probably needs a lot of tuning as indicated by massive number of estimated rows, but that's besides the point. Regardless of the complexity of the query, it should not be requesting 3 gigabytes of memory upon execution.
How do I prevent this behavior? I've tried the following:
DBCC FREEPROCCACHE to clear plan cache. This accomplished nothing.
Setting RECOMPILE option on both SP and SQL level. Again, this does nothing.
Messing around with MAXDOP option, from 0 to 8. Same issue.
The query returns about ~1k rows on average, and it does look into a table with more than 3 million rows with about 4 tables being joined. Executing the query returns the result in less than 3 seconds in majority of the cases.
Edit:
One more thing, using query hints is not really viable for this case since the parameters vary greatly for our case.
Edit2:
Uploaded execution plan upon request
Edit3:
I've tried rebuilding/reorganizing fragmented indices. Apparently, there were few but nothing too serious. Anyhow, this didn't reduce the amount of memory granted and didn't reduce the number of estimated rows (If this is somehow related).
You say optimizing the query is besides the point, but actually it's actually just the point. When a query is executed, SQL Server will -after generating the execution plan- reserve the memory needed for executing the query. The more rows intermediate results are estimated to hold the more memory is estimated to be required.
So, rewrite your query and/or create new indexes to get a decent query plan. A quick glance at the query plan shows some nested loops without join predicates and a number of table scans of which probably only a few records are used.

My execution plan claims that 93% of my 25s long stored procedure were spent on a 2s long query. How is that possible?

I've got a stored procedure which used to take around 25s to execute.
I've used the Execution plan feature of SSMS to track down the performance bottleneck, and have identified that I had a very expansive query where I was auto-joining several times on a single view. I cached it into a CTE, launched again my stored procedure, checked that the relative weight of that specific query in my batch had dropped from 30% to 2%, and started looking for further optimization opportunities.
Actually, the view that I had just cached was used all over the place, so I decided to store the values I needed into a #local table, and to use this table everywhere in my stored procedure. 93% of my batch is now devoted to this line :
insert into #vwActivityCache
select * from vwActivity where n in (#n,#n-1,#n-2)
And this line takes around 2s to execute. (#vwActivityCache contains around 10k rows)
So far, so good.
The thing is that my stored procedure still takes 25s to execute. (after the first exec which takes longer)
I've tried commenting all the queries after the above insert, and the execution takes 2s, as expected.
I've speculated that it could be caused by the time needed to transfer the data back to my sql client (despite the client statistics didn't imply this at all), so I tried removing the final select of the procedure (which now returns nothing), but I'm still stuck at 25s. I've also tried executing directly from the sql server box, 25s as well.
If I remove everything but the local table declaration and the insert that populates it, the stored procedure takes 2s to execute, as expected.
For each query making use of my #vwActivityCache table that I uncomment, the execution time increases by a few seconds (even-though the execution plan claims the uncommented query took 0% of the batch time to execute), till I reach my initial 25s when everything is uncommented.
Unfortunately I can't post the stored procedure nor the execution plan here, but I was wondering if someone had any idea of the reasons that could cause a 2s query to take 93% of the execution time of a 25s procedure !
Update : switching #vwActivityCache to a temp table (#vwActivityCache ) reduced the execution time from 25s to 6s.
The costs shown in even the actual Execution plan are based on estimates and need to be taken with a big pinch of salt.
As soon as you introduce a table variable the estimates will probably be wrong as statistics are not maintained for table variables and they are based on the assumption that the table variable only has one row.
You could try a #temporary table as at least that will have statistics created for it meaning the costs shown in the plan may be a bit more accurate (and it might then choose a different plan based on this anyway) .
How many records you have in #vwActivityCache?
A few guesses:
If there are many of them (depends on number of records and record size) temporary table
could be better, because you can create index on it.
If you select just a few values from #vwActivityCache maybe it is worth to copy them to another variable table?

SQL Server cache question

When I run a certain stored procedure for the first time it takes about 2 minutes to finish. When I run it for the second time it finished in about 15 seconds. I'm assuming that this is because everything is cached after the first run. Is it possible for me to "warm the cache" before I run this procedure for the first time? Is the cached information only used when I call the same stored procedure with the same parameters again or will it be used if I call the same stored procedure with different params?
When you peform your query, the data is read into memory in blocks. These blocks remain in memory but they get "aged". This means the blocks are tagged with the last access and when Sql Server requires another block for a new query and the memory cache is full, the least recently used block (the oldest) is kicked out of memory. (In most cases - full tables scan blocks are instantly aged to prevent full table scans overrunning memory and choking the server).
What is happening here is that the data blocks in memory from the first query haven't been kicked out of memory yet so can be used for your second query, meaning disk access is avoided and performance is improved.
So what your question is really asking is "can I get the data blocks I need into memory without reading them into memory (actually doing a query)?". The answer is no, unless you want to cache the entire tables and have them reside in memory permanently which, from the query time (and thus data size) you are describing, probably isn't a good idea.
Your best bet for performance improvement is looking at your query execution plans and seeing whether changing your indexes might give a better result. There are two major areas that can improve performance here:
creating an index where the query could use one to avoid inefficient queries and full table scans
adding more columns to an index to avoid a second disk read. For example, you have a query that returns columns A, and B with a where clause on A and C and you have an index on column A. Your query will use the index for column A requiring one disk read but then require a second disk hit to get columns B and C. If the index had all columns A, B and C in it the second disk hit to get the data can be avoided.
I don't think that generating the execution plan will cost more that 1 second.
I believe that the difference between first and second run is caused by caching the data in memory.
The data in the cache can be reused by any further query (stored procedure or simple select).
You can 'warm' the cache by reading the data through any select that reads the same data. But that will even cost about 90 seconds as well.
You can check the execution plan to find out which tables and indexes your query uses. You can then execute some SQL to get the data into the cache, depending on what you see.
If you see a clustered index seek, you can simply do SELECT * FROM my_big_table to force all the table's data pages into the cache.
If you see a non-clustered index seek, you could try SELECT first_column_in_index FROM my_big_table.
To force a load of a specific index, you can also use the WITH(INDEX(index)) table hint in your cache warmup queries.
SQL server cache data read from disc.
Consecutive reads will do less IO.
This is of great help since disk IO is usually the bottleneck.
More at:
http://blog.sqlauthority.com/2014/03/18/sql-server-performance-do-it-yourself-caching-with-memcached-vs-automated-caching-with-safepeak/
The execution plan (the cached info for your procedure) is reused every time, even with different parameters. It is one of the benefits of using stored procs.
The very first time a stored procedure is executed, SQL Server generates an execution plan and puts it in the procedure cache.
Certain changes to the database can trigger an automatic update of the execution plan (and you can also explicitly demand a recompile).
Execution plans are dropped from the procedure cache based an their "age". (from MSDN: Objects infrequently referenced are soon eligible for deallocation, but are not actually deallocated unless memory is required for other objects.)
I don't think there is any way to "warm the cache", except to perform the stored proc once. This will guarantee that there is an execution plan in the cache and any subsequent calls will reuse it.
more detailed information is available in the MSDN documentation: http://msdn.microsoft.com/en-us/library/ms181055(SQL.90).aspx