A simple query joining 2 tables:[code="sql"]select * from t1 join t2 on t1.id = t2.id[/code]t1 is a table with only column id with a user defined statistic with norecompute. t1 is very volatile and stores temporary id's. The norecompute is to prevent recompilations (the actual query is much larger, I've trimmed it down to the essential part).t2 is a table with id as pk and clustered index.For my test I have put 5 id's in t1 and a million in t2.The execution plan shows a table scan on t1 and a clustered index seek on t2. The nested loop operator probes t2 using the results from t1. The nested loop operator shows a high number for the estimated nr of rows. Clearly it can never be higher than 5 but it says 10000.And when I set the compatibility level to 2012 the estimate is 5!The problem is that these volatile tables storing temporary ids with norecompute stats are quite intensively used in many queries. The wrong estimation is propagated to the rest of the query plans and this turns out to be not optimal. Query duration goes from 5ms in 2012 to 200ms in 2014 comp level and this will hurt performance when execution frequency goes up. And we are not too keen on putting databases in older compatibility levels.Exec plans for 2014 and 2012 attached.[code="sql"]if object_id('dbo.t1') is not null drop table dbo.t1goif object_id('dbo.t2') is not null drop table dbo.t2gocreate table dbo.t1(id int not null)gocreate statistics stat_id on dbo.t1(id) with norecomputego--insert 5 integers into t1insert into dbo.t1 values(1),(2),(3),(4),(5)gocreate table dbo.t2(id int not null constraint pk_demotable primary key nonclustered (id asc)) go--insert 1000000 integers into t2;with e1(n) as( select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1 union all select 1), -- 10e2(n) as (select 1 from e1 cross join e1 as a), -- 10*10e3(n) as (select 1 from e1 cross join e2), -- 10*100e6(n) as (select 1 from e3 cross join e3 as b), -- 1000*1000ints(n) as (select n = row_number() over (order by n) from e6)insert into t2 (id) select n from intsgo--Examine exec plan in 2012 and 2014 compatibility modeselect * from t1 join t2 on t1.id = t2.id go[/code]
↧