惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
量子位
腾讯CDC
A
About on SuperTechFans
小众软件
小众软件
Microsoft Azure Blog
Microsoft Azure Blog
T
Tailwind CSS Blog
V
V2EX
B
Blog RSS Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
GbyAI
GbyAI
Recent Announcements
Recent Announcements
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
罗磊的独立博客
宝玉的分享
宝玉的分享
WordPress大学
WordPress大学
大猫的无限游戏
大猫的无限游戏
IT之家
IT之家
V
Visual Studio Blog
D
DataBreaches.Net
博客园 - 三生石上(FineUI控件)
月光博客
月光博客
有赞技术团队
有赞技术团队

博客园 - Yuejun Sun

Office 365 Certificate Exam Resources How to: Grant Permission on Development Severs as Batch for Windows Authentications Step By Step Guide to configure the “Replicating directory changes” for SharePoint 2010 and 2013 分享:Windows Azure 电子书 Sharepoint 2013配置失败:SQL 实例没有将“MaxDegree of Parallelism”设置为1 免费注册Sharepoint 2013 站点 巧用Discussions列表归档Outlook邮件 Special Offer: Watch Three In-Depth SQL Server Courses by SQLskills (FREE) How to: Database Service fails to start due to log full of model database 续:有关SQL SERVER分布统计的问题 有关SQL Server分布统计的问题 第三章:分析基本查询的文本和XML执行计划 续第二章:分析基本查询的图形执行计划--表连接 第二章:分析基本查询的图形执行计划 第一章:执行计划基本知识--文本执行计划和XML执行计划 第一章:执行计划基本知识--范例入门 第一章:执行计划基本知识 免费下载:Inside the SQL Server Query Optimizer(查询优化器内幕) 查询优化器如何使用统计—Part I
Forward:Stale statistics on a newly created temporary tab...
Yuejun Sun · 2012-08-16 · via 博客园 - Yuejun Sun

For the details, please visit the following address:

www.sqlworkshops.com.


When you create a temporary table you expect a new table with no past history (statistics based on past existence), this is not true if you have less than 6 updates to the temporary table. This might lead to poor performance of queries which are sensitive to the content of temporary tables.

I was optimizing SQL Server Performance at one of my customers who provides search functionality on their website. They use stored procedure with temporary table for the search. The performance of the search depended on who searched what in the past, option (recompile) by itself had no effect. Sometimes a simple search led to timeout because of non-optimal plan usage due to this behavior. This is not a plan caching issue rather temporary table statistics caching issue, which was part of the temporary object caching feature that was introduced in SQL Server 2005 and is also present in SQL Server 2008 and SQL Server 2012. In this customer case we implemented a workaround to avoid this issue (see below for example for workarounds).

When temporary tables are cached, the statistics are not newly created rather cached from the past and updated based on automatic update statistics threshold. Caching temporary tables/objects is good for performance, but caching stale statistics from the past is not optimal.

We can work around this issue by disabling temporary table caching by explicitly executing a DDL statement on the temporary table. One possibility is to execute an alter table statement, but this can lead to duplicate constraint name error on concurrent stored procedure execution. The other way to work around this is to create an index.

I think there might be many customers in such a situation without knowing that stale statistics are being cached along with temporary table leading to poor performance.

Ideal solution is to have more aggressive statistics update when the temporary table has less number of rows when temporary table caching is used. I will open a connect item to report this issue.

Meanwhile you can mitigate the issue by creating an index on the temporary table. You can monitor active temporary tables using Windows Server Performance Monitor counter: SQL Server: General Statistics->Active Temp Tables.

The script to understand the issue and the workaround is listed below:
set nocount on
set statistics time off
set statistics io off
drop table tab7
go
create table tab7 (c1 int primary key clustered, c2 int, c3 char(200))
go
create index test on tab7(c2, c1, c3)
go
begin tran
declare @i int
set @i = 1
while @i <= 50000
begin
insert into tab7 values (@i, 1, 'a')
set @i = @i + 1
end
commit tran
go
insert into tab7 values (50001, 1, 'a')
go
checkpoint
go
drop proc test_slow
go
create proc test_slow @i int
as
begin
declare @j int
create table #temp1 (c1 int primary key)
insert into #temp1 (c1) select @i
select @j = t7.c1 from tab7 t7 inner join #temp1 t on (t7.c2 = t.c1)
end
go
dbcc dropcleanbuffers
set statistics time on
set statistics io on
go
--high reads as expected for parameter '1'
exec test_slow 1
go
dbcc dropcleanbuffers
go
--high reads that are not expected for parameter '2'
exec test_slow 2
go
drop proc test_with_recompile
go
create proc test_with_recompile @i int
as
begin
declare @j int
create table #temp1 (c1 int primary key)
insert into #temp1 (c1) select @i
select @j = t7.c1 from tab7 t7 inner join #temp1 t on (t7.c2 = t.c1)
option (recompile)
end
go
dbcc dropcleanbuffers
set statistics time on
set statistics io on
go
--high reads as expected for parameter '1'
exec test_with_recompile 1
go
dbcc dropcleanbuffers
go
--high reads that are not expected for parameter '2'
--low reads on 3rd execution as expected for parameter '2'
exec test_with_recompile 2
go
drop proc test_with_alter_table_recompile
go
create proc test_with_alter_table_recompile @i int
as
begin
declare @j int
create table #temp1 (c1 int primary key)
--to avoid caching of temporary tables one can create a constraint
--but this might lead to duplicate constraint name error on concurrent usage
alter table #temp1 add constraint test123 unique(c1)
insert into #temp1 (c1) select @i
select @j = t7.c1 from tab7 t7 inner join #temp1 t on (t7.c2 = t.c1)
option (recompile)
end
go
dbcc dropcleanbuffers
set statistics time on
set statistics io on
go
--high reads as expected for parameter '1'
exec test_with_alter_table_recompile 1
go
dbcc dropcleanbuffers
go
--low reads as expected for parameter '2'
exec test_with_alter_table_recompile 2
go
drop proc test_with_index_recompile
go
create proc test_with_index_recompile @i int
as
begin
declare @j int
create table #temp1 (c1 int primary key)
--to avoid caching of temporary tables one can create an index
create index test on #temp1(c1)
insert into #temp1 (c1) select @i
select @j = t7.c1 from tab7 t7 inner join #temp1 t on (t7.c2 = t.c1)
option (recompile)
end
go
set statistics time on
set statistics io on
dbcc dropcleanbuffers
go
--high reads as expected for parameter '1'
exec test_with_index_recompile 1
go
dbcc dropcleanbuffers
go
--low reads as expected for parameter '2'
exec test_with_index_recompile 2
go