After Restoring Log Shipping to Secondary Server, First Stored Procedure Execution is SlowSQL Server clears plan cache and execution stats periodicallyDifferences Between Setting Up Transaction Log Shipping through Wizard vs ScriptsSQL Server Log shipping standby db stuck restoringLog Shipping -Monitor Server Down - Copying happening but not restoring on secondaryAlter of stored procedure and execution performanceLog Shipping SQL Server 2012Clearing Log Shipping config Secondary server inaccessibleProblem Configuring Log Shipping for DR ServerRestoring Job failed with error 'Could not find a log backup file that could be applied' on Log Shipping in SQL Server (Secondary)?Log Shipping: Bulk Remove Alerts of already deleted primary and secondary databasesSQL server log shipping - dry-run data modification script on secondary then resume log shippingTransaction Log Shipping Primary Server Status not Shown on Secondary Monitoring Server
Image processing: Removal of two spots in fundus images
Does Nitrogen inside commercial airliner wheels prevent blowouts on touchdown?
Why were helmets and other body armour not commonplace in the 1800s?
Plot twist where the antagonist wins
Flying domestically in the US, is my State Issued ID all I need to get past security?
Statue View: 2, 3, 5, 7
Does the unit of measure matter when you are solving for the diameter of a circumference?
Adding spaces to string based on list
Why does a perfectly-identical repetition of a drawing command given within an earlier loop 𝘯𝘰𝘵 produce exactly the same line?
What is memelemum?
How do Human Traits Work?
Are these reasonable traits for someone with autism?
When and what was the first 3D acceleration device ever released?
Why doesn't the Earth accelerate towards the Moon?
Looking for a soft substance that doesn't dissolve underwater
What are these arcade games in Ghostbusters 1984?
Cipher Block Chaining - How do you change the plaintext of all blocks?
Where have Brexit voters gone?
Employer asking for online access to bank account - Is this a scam?
Simple function that simulates survey results based on sample size and probability
Why are C64 games inconsistent with which joystick port they use?
Is it possible to play as a necromancer skeleton?
Binary Search in C++17
Crossing US border with music files I'm legally allowed to possess
After Restoring Log Shipping to Secondary Server, First Stored Procedure Execution is Slow
SQL Server clears plan cache and execution stats periodicallyDifferences Between Setting Up Transaction Log Shipping through Wizard vs ScriptsSQL Server Log shipping standby db stuck restoringLog Shipping -Monitor Server Down - Copying happening but not restoring on secondaryAlter of stored procedure and execution performanceLog Shipping SQL Server 2012Clearing Log Shipping config Secondary server inaccessibleProblem Configuring Log Shipping for DR ServerRestoring Job failed with error 'Could not find a log backup file that could be applied' on Log Shipping in SQL Server (Secondary)?Log Shipping: Bulk Remove Alerts of already deleted primary and secondary databasesSQL server log shipping - dry-run data modification script on secondary then resume log shippingTransaction Log Shipping Primary Server Status not Shown on Secondary Monitoring Server
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
We've set up log shipping to a secondary SQL server on Standby/ Read-Only to offload all SSRS report generation.
This works fine within the restrictions imposed by:
- Kicking out the user during the transaction log restore (we got around this by setting up multiple instances and restoring the most recent transaction logs using a round-robin schedule)
- The data being out of date by, at most, the time-frame indicated by the scheduled transaction log backup/ restore job.
Unfortunately, the first time any/ all stored procedure are run, after the transaction log was restored, it takes a much longer time to complete than normal. All subsequent executions of that same stored procedure complete within the expected time. If we then execute another stored procedure, the first time it is slow and all subsequent executions complete in the expected time.
For reference, the difference in execution is ~00:02 normally compared to ~01:00 on the first run.
I assume this has something to do with either the server execution statistics or the stored procedure parameter sniffing/ stored execution plan.
Is there any way to get around this issue? Or is this inherent to the transaction log restore?
If it was just the very first execution of any stored procedure we could get around this easily by executing any stored procedure upon restore, but it appears to affect the first time all stored procedures are executed.
I tried running count( * )
on the 11 tables the stored procedure I'm using for testing touches. The first run took 00:32, and subsequent count(*) took 00:00. Unfortunately, this did not have any impact on the first run of the stored procedure.
I don't see any results on either my primary or secondary servers for is_temporary
stats, either before or after execution of a stored procedure.
I'm currently on SQL Server 2012
Query Exection Plan:
The query execution plan at first glance appears significantly different, however, upon saving the execution plan and opening the .sqlplan file generated they are exactly the same. The difference appears to be coming from the different versions of SSMS I am using, 2014 on the primary server and 2018 on the secondary. When viewing the execution plan on the secondary it shows underneath every node's % and time cost ### of ### (##%) - neither those numbers, nor the actual execution plan change upon further executions.
I also included client statistics and they show almost exactly the same, the only difference being the primary server executes with 1.4 seconds of Wait time on server replies and the secondary takes 81.3 seconds.
I do see a large number of PAGEIOLATCH_SH locks from the first execution, as you predicted:
diff after first exec vs diff after second exec
waiting_tasks_count 10903 918
wait_time_ms 411129 12768
One of the odd things about this situation, is, except for the round-robin multiple instances part of the setup we already have our production SSRS server reading from a standby/ read-only database that is fed by periodic transaction logs and do not experience these slow downs on the first execution of a stored procedure. Our users are kicked off every time the transaction log is restored, though, which is the problem the above setup is supposed to resolve.
sql-server sql-server-2012 stored-procedures restore log-shipping
add a comment |
We've set up log shipping to a secondary SQL server on Standby/ Read-Only to offload all SSRS report generation.
This works fine within the restrictions imposed by:
- Kicking out the user during the transaction log restore (we got around this by setting up multiple instances and restoring the most recent transaction logs using a round-robin schedule)
- The data being out of date by, at most, the time-frame indicated by the scheduled transaction log backup/ restore job.
Unfortunately, the first time any/ all stored procedure are run, after the transaction log was restored, it takes a much longer time to complete than normal. All subsequent executions of that same stored procedure complete within the expected time. If we then execute another stored procedure, the first time it is slow and all subsequent executions complete in the expected time.
For reference, the difference in execution is ~00:02 normally compared to ~01:00 on the first run.
I assume this has something to do with either the server execution statistics or the stored procedure parameter sniffing/ stored execution plan.
Is there any way to get around this issue? Or is this inherent to the transaction log restore?
If it was just the very first execution of any stored procedure we could get around this easily by executing any stored procedure upon restore, but it appears to affect the first time all stored procedures are executed.
I tried running count( * )
on the 11 tables the stored procedure I'm using for testing touches. The first run took 00:32, and subsequent count(*) took 00:00. Unfortunately, this did not have any impact on the first run of the stored procedure.
I don't see any results on either my primary or secondary servers for is_temporary
stats, either before or after execution of a stored procedure.
I'm currently on SQL Server 2012
Query Exection Plan:
The query execution plan at first glance appears significantly different, however, upon saving the execution plan and opening the .sqlplan file generated they are exactly the same. The difference appears to be coming from the different versions of SSMS I am using, 2014 on the primary server and 2018 on the secondary. When viewing the execution plan on the secondary it shows underneath every node's % and time cost ### of ### (##%) - neither those numbers, nor the actual execution plan change upon further executions.
I also included client statistics and they show almost exactly the same, the only difference being the primary server executes with 1.4 seconds of Wait time on server replies and the secondary takes 81.3 seconds.
I do see a large number of PAGEIOLATCH_SH locks from the first execution, as you predicted:
diff after first exec vs diff after second exec
waiting_tasks_count 10903 918
wait_time_ms 411129 12768
One of the odd things about this situation, is, except for the round-robin multiple instances part of the setup we already have our production SSRS server reading from a standby/ read-only database that is fed by periodic transaction logs and do not experience these slow downs on the first execution of a stored procedure. Our users are kicked off every time the transaction log is restored, though, which is the problem the above setup is supposed to resolve.
sql-server sql-server-2012 stored-procedures restore log-shipping
I'd guess it's due to the plan cache being cleared from the log restore. After your follow on run of the procedure, a new plan is generated and stored in cache and reused which is why you'd notice the performance improvement in subsequent runs. Check out this answer on ways to verify / check this.
– scsimon
May 13 at 16:18
Upon querying from sys.dm_exec_query_stats, the oldest plan cache doesn't seem to change, but the newest one (after sorting in desc by creation_time) is updated and appears to be copied over during Log Shipping, as they have the same time stamps after the transaction log restore has completed. It doesn't seem to have any effect on the slow first execution, though.
– RIanGillis
May 13 at 17:37
add a comment |
We've set up log shipping to a secondary SQL server on Standby/ Read-Only to offload all SSRS report generation.
This works fine within the restrictions imposed by:
- Kicking out the user during the transaction log restore (we got around this by setting up multiple instances and restoring the most recent transaction logs using a round-robin schedule)
- The data being out of date by, at most, the time-frame indicated by the scheduled transaction log backup/ restore job.
Unfortunately, the first time any/ all stored procedure are run, after the transaction log was restored, it takes a much longer time to complete than normal. All subsequent executions of that same stored procedure complete within the expected time. If we then execute another stored procedure, the first time it is slow and all subsequent executions complete in the expected time.
For reference, the difference in execution is ~00:02 normally compared to ~01:00 on the first run.
I assume this has something to do with either the server execution statistics or the stored procedure parameter sniffing/ stored execution plan.
Is there any way to get around this issue? Or is this inherent to the transaction log restore?
If it was just the very first execution of any stored procedure we could get around this easily by executing any stored procedure upon restore, but it appears to affect the first time all stored procedures are executed.
I tried running count( * )
on the 11 tables the stored procedure I'm using for testing touches. The first run took 00:32, and subsequent count(*) took 00:00. Unfortunately, this did not have any impact on the first run of the stored procedure.
I don't see any results on either my primary or secondary servers for is_temporary
stats, either before or after execution of a stored procedure.
I'm currently on SQL Server 2012
Query Exection Plan:
The query execution plan at first glance appears significantly different, however, upon saving the execution plan and opening the .sqlplan file generated they are exactly the same. The difference appears to be coming from the different versions of SSMS I am using, 2014 on the primary server and 2018 on the secondary. When viewing the execution plan on the secondary it shows underneath every node's % and time cost ### of ### (##%) - neither those numbers, nor the actual execution plan change upon further executions.
I also included client statistics and they show almost exactly the same, the only difference being the primary server executes with 1.4 seconds of Wait time on server replies and the secondary takes 81.3 seconds.
I do see a large number of PAGEIOLATCH_SH locks from the first execution, as you predicted:
diff after first exec vs diff after second exec
waiting_tasks_count 10903 918
wait_time_ms 411129 12768
One of the odd things about this situation, is, except for the round-robin multiple instances part of the setup we already have our production SSRS server reading from a standby/ read-only database that is fed by periodic transaction logs and do not experience these slow downs on the first execution of a stored procedure. Our users are kicked off every time the transaction log is restored, though, which is the problem the above setup is supposed to resolve.
sql-server sql-server-2012 stored-procedures restore log-shipping
We've set up log shipping to a secondary SQL server on Standby/ Read-Only to offload all SSRS report generation.
This works fine within the restrictions imposed by:
- Kicking out the user during the transaction log restore (we got around this by setting up multiple instances and restoring the most recent transaction logs using a round-robin schedule)
- The data being out of date by, at most, the time-frame indicated by the scheduled transaction log backup/ restore job.
Unfortunately, the first time any/ all stored procedure are run, after the transaction log was restored, it takes a much longer time to complete than normal. All subsequent executions of that same stored procedure complete within the expected time. If we then execute another stored procedure, the first time it is slow and all subsequent executions complete in the expected time.
For reference, the difference in execution is ~00:02 normally compared to ~01:00 on the first run.
I assume this has something to do with either the server execution statistics or the stored procedure parameter sniffing/ stored execution plan.
Is there any way to get around this issue? Or is this inherent to the transaction log restore?
If it was just the very first execution of any stored procedure we could get around this easily by executing any stored procedure upon restore, but it appears to affect the first time all stored procedures are executed.
I tried running count( * )
on the 11 tables the stored procedure I'm using for testing touches. The first run took 00:32, and subsequent count(*) took 00:00. Unfortunately, this did not have any impact on the first run of the stored procedure.
I don't see any results on either my primary or secondary servers for is_temporary
stats, either before or after execution of a stored procedure.
I'm currently on SQL Server 2012
Query Exection Plan:
The query execution plan at first glance appears significantly different, however, upon saving the execution plan and opening the .sqlplan file generated they are exactly the same. The difference appears to be coming from the different versions of SSMS I am using, 2014 on the primary server and 2018 on the secondary. When viewing the execution plan on the secondary it shows underneath every node's % and time cost ### of ### (##%) - neither those numbers, nor the actual execution plan change upon further executions.
I also included client statistics and they show almost exactly the same, the only difference being the primary server executes with 1.4 seconds of Wait time on server replies and the secondary takes 81.3 seconds.
I do see a large number of PAGEIOLATCH_SH locks from the first execution, as you predicted:
diff after first exec vs diff after second exec
waiting_tasks_count 10903 918
wait_time_ms 411129 12768
One of the odd things about this situation, is, except for the round-robin multiple instances part of the setup we already have our production SSRS server reading from a standby/ read-only database that is fed by periodic transaction logs and do not experience these slow downs on the first execution of a stored procedure. Our users are kicked off every time the transaction log is restored, though, which is the problem the above setup is supposed to resolve.
sql-server sql-server-2012 stored-procedures restore log-shipping
sql-server sql-server-2012 stored-procedures restore log-shipping
edited May 13 at 21:01
RIanGillis
asked May 13 at 15:41
RIanGillisRIanGillis
555
555
I'd guess it's due to the plan cache being cleared from the log restore. After your follow on run of the procedure, a new plan is generated and stored in cache and reused which is why you'd notice the performance improvement in subsequent runs. Check out this answer on ways to verify / check this.
– scsimon
May 13 at 16:18
Upon querying from sys.dm_exec_query_stats, the oldest plan cache doesn't seem to change, but the newest one (after sorting in desc by creation_time) is updated and appears to be copied over during Log Shipping, as they have the same time stamps after the transaction log restore has completed. It doesn't seem to have any effect on the slow first execution, though.
– RIanGillis
May 13 at 17:37
add a comment |
I'd guess it's due to the plan cache being cleared from the log restore. After your follow on run of the procedure, a new plan is generated and stored in cache and reused which is why you'd notice the performance improvement in subsequent runs. Check out this answer on ways to verify / check this.
– scsimon
May 13 at 16:18
Upon querying from sys.dm_exec_query_stats, the oldest plan cache doesn't seem to change, but the newest one (after sorting in desc by creation_time) is updated and appears to be copied over during Log Shipping, as they have the same time stamps after the transaction log restore has completed. It doesn't seem to have any effect on the slow first execution, though.
– RIanGillis
May 13 at 17:37
I'd guess it's due to the plan cache being cleared from the log restore. After your follow on run of the procedure, a new plan is generated and stored in cache and reused which is why you'd notice the performance improvement in subsequent runs. Check out this answer on ways to verify / check this.
– scsimon
May 13 at 16:18
I'd guess it's due to the plan cache being cleared from the log restore. After your follow on run of the procedure, a new plan is generated and stored in cache and reused which is why you'd notice the performance improvement in subsequent runs. Check out this answer on ways to verify / check this.
– scsimon
May 13 at 16:18
Upon querying from sys.dm_exec_query_stats, the oldest plan cache doesn't seem to change, but the newest one (after sorting in desc by creation_time) is updated and appears to be copied over during Log Shipping, as they have the same time stamps after the transaction log restore has completed. It doesn't seem to have any effect on the slow first execution, though.
– RIanGillis
May 13 at 17:37
Upon querying from sys.dm_exec_query_stats, the oldest plan cache doesn't seem to change, but the newest one (after sorting in desc by creation_time) is updated and appears to be copied over during Log Shipping, as they have the same time stamps after the transaction log restore has completed. It doesn't seem to have any effect on the slow first execution, though.
– RIanGillis
May 13 at 17:37
add a comment |
1 Answer
1
active
oldest
votes
There are a few possible things going on here, here's a non-exhaustive list:
- the execution plan cache is cleared by the log restore, so plans will need to be recompiled the first time. If your plans have long compile times, this could explain the difference. You didn't mention exactly how long the delay is on the first run compared to the subsequent runs
- this one seems like the least likely - you can see your plan compilation time in actual execution plan XML
- the buffer pool is also cleared during the restore, so all data has to be read from disk on the first execution
- if this is the case, you'll likely see high
PAGEIOLATCH*
waits during the initial run if you check wait stats
- if this is the case, you'll likely see high
Some things you could do to mitigate this are
- "warm up" the buffer cache (by reading all data from important tables into memory using
SELECT COUNT(*) FROM dbo.YourTable
), - "warm up" the proc cache by running all the critical stored procedures as a post-restore step
Providing us with a "fast" and "slow" example of an execution plan could help us track down exactly which thing is happening.
If you are on SQL Server 2012 or newer, then it's possible that sync stats updates are causing the delay. These "readable secondary stats" get created in TempDB, since the log shipping secondary is read-only. You can read more about that here (the article is about AGs, but the same thing applies in this scenario):
AlwaysOn: Making latest statistics available on Readable Secondary, Read-Only database and Database Snapshot
If this is the problem causing your slowdown, then one solution would be to find those stats, and then create them in the production database, so that they are up-to-date and available after the restore. You can look for temp stats with this query:
SELECT * FROM sys.stats WHERE is_temporary = 1;
Based on the wait stats you provided, and the fact that the plans are the same, this is pretty conclusively due to the buffer pool being cleared by the log restore.
On a normal run, you get 12,768 ms (almost 13 seconds) of IO waits.
On the first run, you get 411,129 ms (almost 7 minutes) of IO waits.
The SELECT COUNT(*)
approach you tried may not have helped due to different indexes being used by the actual procedure vs the COUNT(*)
query. You have a few options here:
- Go through each execution plan and make note of the indexes being used, and then pull those indexes into memory as a post-restore step - using index hints this time (
SELECT COUNT(*) FROM dbo.YourTable WITH (INDEX (IX_Index_Being_Used_By_Proc))
) - Go through the process of scripting out a process to run each procedure as a post-restore step (this seems a bit easier than option 1)
- Tune the queries so that they don't need to do so many reads (not sure how feasible this is)
- Speed up the I/O subsystem - get faster disks, local SSDs, more channels to the SAN, etc (this is probably the hardest and most expensive option
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "182"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f238034%2fafter-restoring-log-shipping-to-secondary-server-first-stored-procedure-executi%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
There are a few possible things going on here, here's a non-exhaustive list:
- the execution plan cache is cleared by the log restore, so plans will need to be recompiled the first time. If your plans have long compile times, this could explain the difference. You didn't mention exactly how long the delay is on the first run compared to the subsequent runs
- this one seems like the least likely - you can see your plan compilation time in actual execution plan XML
- the buffer pool is also cleared during the restore, so all data has to be read from disk on the first execution
- if this is the case, you'll likely see high
PAGEIOLATCH*
waits during the initial run if you check wait stats
- if this is the case, you'll likely see high
Some things you could do to mitigate this are
- "warm up" the buffer cache (by reading all data from important tables into memory using
SELECT COUNT(*) FROM dbo.YourTable
), - "warm up" the proc cache by running all the critical stored procedures as a post-restore step
Providing us with a "fast" and "slow" example of an execution plan could help us track down exactly which thing is happening.
If you are on SQL Server 2012 or newer, then it's possible that sync stats updates are causing the delay. These "readable secondary stats" get created in TempDB, since the log shipping secondary is read-only. You can read more about that here (the article is about AGs, but the same thing applies in this scenario):
AlwaysOn: Making latest statistics available on Readable Secondary, Read-Only database and Database Snapshot
If this is the problem causing your slowdown, then one solution would be to find those stats, and then create them in the production database, so that they are up-to-date and available after the restore. You can look for temp stats with this query:
SELECT * FROM sys.stats WHERE is_temporary = 1;
Based on the wait stats you provided, and the fact that the plans are the same, this is pretty conclusively due to the buffer pool being cleared by the log restore.
On a normal run, you get 12,768 ms (almost 13 seconds) of IO waits.
On the first run, you get 411,129 ms (almost 7 minutes) of IO waits.
The SELECT COUNT(*)
approach you tried may not have helped due to different indexes being used by the actual procedure vs the COUNT(*)
query. You have a few options here:
- Go through each execution plan and make note of the indexes being used, and then pull those indexes into memory as a post-restore step - using index hints this time (
SELECT COUNT(*) FROM dbo.YourTable WITH (INDEX (IX_Index_Being_Used_By_Proc))
) - Go through the process of scripting out a process to run each procedure as a post-restore step (this seems a bit easier than option 1)
- Tune the queries so that they don't need to do so many reads (not sure how feasible this is)
- Speed up the I/O subsystem - get faster disks, local SSDs, more channels to the SAN, etc (this is probably the hardest and most expensive option
add a comment |
There are a few possible things going on here, here's a non-exhaustive list:
- the execution plan cache is cleared by the log restore, so plans will need to be recompiled the first time. If your plans have long compile times, this could explain the difference. You didn't mention exactly how long the delay is on the first run compared to the subsequent runs
- this one seems like the least likely - you can see your plan compilation time in actual execution plan XML
- the buffer pool is also cleared during the restore, so all data has to be read from disk on the first execution
- if this is the case, you'll likely see high
PAGEIOLATCH*
waits during the initial run if you check wait stats
- if this is the case, you'll likely see high
Some things you could do to mitigate this are
- "warm up" the buffer cache (by reading all data from important tables into memory using
SELECT COUNT(*) FROM dbo.YourTable
), - "warm up" the proc cache by running all the critical stored procedures as a post-restore step
Providing us with a "fast" and "slow" example of an execution plan could help us track down exactly which thing is happening.
If you are on SQL Server 2012 or newer, then it's possible that sync stats updates are causing the delay. These "readable secondary stats" get created in TempDB, since the log shipping secondary is read-only. You can read more about that here (the article is about AGs, but the same thing applies in this scenario):
AlwaysOn: Making latest statistics available on Readable Secondary, Read-Only database and Database Snapshot
If this is the problem causing your slowdown, then one solution would be to find those stats, and then create them in the production database, so that they are up-to-date and available after the restore. You can look for temp stats with this query:
SELECT * FROM sys.stats WHERE is_temporary = 1;
Based on the wait stats you provided, and the fact that the plans are the same, this is pretty conclusively due to the buffer pool being cleared by the log restore.
On a normal run, you get 12,768 ms (almost 13 seconds) of IO waits.
On the first run, you get 411,129 ms (almost 7 minutes) of IO waits.
The SELECT COUNT(*)
approach you tried may not have helped due to different indexes being used by the actual procedure vs the COUNT(*)
query. You have a few options here:
- Go through each execution plan and make note of the indexes being used, and then pull those indexes into memory as a post-restore step - using index hints this time (
SELECT COUNT(*) FROM dbo.YourTable WITH (INDEX (IX_Index_Being_Used_By_Proc))
) - Go through the process of scripting out a process to run each procedure as a post-restore step (this seems a bit easier than option 1)
- Tune the queries so that they don't need to do so many reads (not sure how feasible this is)
- Speed up the I/O subsystem - get faster disks, local SSDs, more channels to the SAN, etc (this is probably the hardest and most expensive option
add a comment |
There are a few possible things going on here, here's a non-exhaustive list:
- the execution plan cache is cleared by the log restore, so plans will need to be recompiled the first time. If your plans have long compile times, this could explain the difference. You didn't mention exactly how long the delay is on the first run compared to the subsequent runs
- this one seems like the least likely - you can see your plan compilation time in actual execution plan XML
- the buffer pool is also cleared during the restore, so all data has to be read from disk on the first execution
- if this is the case, you'll likely see high
PAGEIOLATCH*
waits during the initial run if you check wait stats
- if this is the case, you'll likely see high
Some things you could do to mitigate this are
- "warm up" the buffer cache (by reading all data from important tables into memory using
SELECT COUNT(*) FROM dbo.YourTable
), - "warm up" the proc cache by running all the critical stored procedures as a post-restore step
Providing us with a "fast" and "slow" example of an execution plan could help us track down exactly which thing is happening.
If you are on SQL Server 2012 or newer, then it's possible that sync stats updates are causing the delay. These "readable secondary stats" get created in TempDB, since the log shipping secondary is read-only. You can read more about that here (the article is about AGs, but the same thing applies in this scenario):
AlwaysOn: Making latest statistics available on Readable Secondary, Read-Only database and Database Snapshot
If this is the problem causing your slowdown, then one solution would be to find those stats, and then create them in the production database, so that they are up-to-date and available after the restore. You can look for temp stats with this query:
SELECT * FROM sys.stats WHERE is_temporary = 1;
Based on the wait stats you provided, and the fact that the plans are the same, this is pretty conclusively due to the buffer pool being cleared by the log restore.
On a normal run, you get 12,768 ms (almost 13 seconds) of IO waits.
On the first run, you get 411,129 ms (almost 7 minutes) of IO waits.
The SELECT COUNT(*)
approach you tried may not have helped due to different indexes being used by the actual procedure vs the COUNT(*)
query. You have a few options here:
- Go through each execution plan and make note of the indexes being used, and then pull those indexes into memory as a post-restore step - using index hints this time (
SELECT COUNT(*) FROM dbo.YourTable WITH (INDEX (IX_Index_Being_Used_By_Proc))
) - Go through the process of scripting out a process to run each procedure as a post-restore step (this seems a bit easier than option 1)
- Tune the queries so that they don't need to do so many reads (not sure how feasible this is)
- Speed up the I/O subsystem - get faster disks, local SSDs, more channels to the SAN, etc (this is probably the hardest and most expensive option
There are a few possible things going on here, here's a non-exhaustive list:
- the execution plan cache is cleared by the log restore, so plans will need to be recompiled the first time. If your plans have long compile times, this could explain the difference. You didn't mention exactly how long the delay is on the first run compared to the subsequent runs
- this one seems like the least likely - you can see your plan compilation time in actual execution plan XML
- the buffer pool is also cleared during the restore, so all data has to be read from disk on the first execution
- if this is the case, you'll likely see high
PAGEIOLATCH*
waits during the initial run if you check wait stats
- if this is the case, you'll likely see high
Some things you could do to mitigate this are
- "warm up" the buffer cache (by reading all data from important tables into memory using
SELECT COUNT(*) FROM dbo.YourTable
), - "warm up" the proc cache by running all the critical stored procedures as a post-restore step
Providing us with a "fast" and "slow" example of an execution plan could help us track down exactly which thing is happening.
If you are on SQL Server 2012 or newer, then it's possible that sync stats updates are causing the delay. These "readable secondary stats" get created in TempDB, since the log shipping secondary is read-only. You can read more about that here (the article is about AGs, but the same thing applies in this scenario):
AlwaysOn: Making latest statistics available on Readable Secondary, Read-Only database and Database Snapshot
If this is the problem causing your slowdown, then one solution would be to find those stats, and then create them in the production database, so that they are up-to-date and available after the restore. You can look for temp stats with this query:
SELECT * FROM sys.stats WHERE is_temporary = 1;
Based on the wait stats you provided, and the fact that the plans are the same, this is pretty conclusively due to the buffer pool being cleared by the log restore.
On a normal run, you get 12,768 ms (almost 13 seconds) of IO waits.
On the first run, you get 411,129 ms (almost 7 minutes) of IO waits.
The SELECT COUNT(*)
approach you tried may not have helped due to different indexes being used by the actual procedure vs the COUNT(*)
query. You have a few options here:
- Go through each execution plan and make note of the indexes being used, and then pull those indexes into memory as a post-restore step - using index hints this time (
SELECT COUNT(*) FROM dbo.YourTable WITH (INDEX (IX_Index_Being_Used_By_Proc))
) - Go through the process of scripting out a process to run each procedure as a post-restore step (this seems a bit easier than option 1)
- Tune the queries so that they don't need to do so many reads (not sure how feasible this is)
- Speed up the I/O subsystem - get faster disks, local SSDs, more channels to the SAN, etc (this is probably the hardest and most expensive option
edited May 14 at 12:58
Forrest
2,8591824
2,8591824
answered May 13 at 16:26
Josh DarnellJosh Darnell
9,26632346
9,26632346
add a comment |
add a comment |
Thanks for contributing an answer to Database Administrators Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f238034%2fafter-restoring-log-shipping-to-secondary-server-first-stored-procedure-executi%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I'd guess it's due to the plan cache being cleared from the log restore. After your follow on run of the procedure, a new plan is generated and stored in cache and reused which is why you'd notice the performance improvement in subsequent runs. Check out this answer on ways to verify / check this.
– scsimon
May 13 at 16:18
Upon querying from sys.dm_exec_query_stats, the oldest plan cache doesn't seem to change, but the newest one (after sorting in desc by creation_time) is updated and appears to be copied over during Log Shipping, as they have the same time stamps after the transaction log restore has completed. It doesn't seem to have any effect on the slow first execution, though.
– RIanGillis
May 13 at 17:37