Sample Header Ad - 728x90

Save CPU cycles on SQL Server Query Plans (Better without Stats than with on wide tables)

3 votes
1 answer
131 views
Assume that a query in question has a very wide set of columns. The query looks like the following: set statistics io,time on; Select a.Col1, a.Col2, b.Col3, b.Col4, c.Col5 From FirstWideTable a Join SecondWideTable b on a.Col6=b.Col7 Join ThirdWideTable c on b.Col8=c.Col9 WHERE a.Col10=@SomeVariable; set statistics io,time off; The above query uses 10 columns of 100 or so (more "selective" queries). SQL Server created statistics on these tables and tables contain effective indexes adressing the predicate (Col10) and while not showing here, assume the PK's are created on the three tables (see demo below): CREATE NONCLUSTERED INDEX NC__a_Col1_Col2_Col6 ON FirstWideTable(Col1 ASC,Col2 ASC, Col3 ASC) INCLUDE (Col10) ON PRIMARY; and similar indexes are available for the Second and Third Wide Tables. If the query is written as a subquery with only the 10 columns required: set statistics io,time on; Select a.Col1, a.Col2, b.Col3, b.Col4, c.Col5 From (SELECT a.Col1, a.Col2,a.Col6,a.Col10 FROM FirstWideTable) a Join (SELECT b.Col4,b.Col5, b.Col7 FROM SecondWideTable) b on a.Col6=b.Col7 Join (c.Col5, c.Col9 FROM ThirdWideTable) c on b.Col8=c.Col9 WHERE a.Col10=@SomeVariable; set statistics io,time off; resulst improve. Elapsed time on the wide tables with statistics show terrible (30 second) elapased time. Each time the query (without statistics running against it) has the actual columns listed in a subquery, the elapsed time drops considerably. QUERY RESULTS - Wide table has statistics - Wide table is the baseline. subqueries results do not have statistics against them, the timing was taken after adding in the subquery that examines only the columns necessary rather than the wide table. CPU Time (ms) Elapsed Time (ms) Wide table result 7265 35459 Subqueried narrow result table 1 5125 31271 Wide table result 6765 33446 Subqueried narrow result table 2 5391 27099 Wide table result 7203 34354 Subqueried narrow result table 3 5843 10321 Result from the theoretical data below: CPU Time (ms) Elapsed Time (ms) Wide table result 109 461 Subqueried narrow result table 1 32 441 Wide table result 78 441 Subqueried narrow result table 2 110 453 Wide table result 62 441 Subqueried narrow result table 3 63 458 Here is how the theoretical data was generated. /* create a dummy source table */ select * into tblSourceTable from(select top 100000 NewID()A, NewID()B from sys.columns)x Generate theoretical data: DECLARE @test2 TABLE ( [ID] [bigint] NULL, [A] [uniqueidentifier] NULL, [B] [uniqueidentifier] NULL, [C] [uniqueidentifier] NULL, [D] [uniqueidentifier] NULL, [E] [uniqueidentifier] NULL, [F] [uniqueidentifier] NULL, [G] [uniqueidentifier] NULL, [H] [uniqueidentifier] NULL, [I] [uniqueidentifier] NULL, [J] [uniqueidentifier] NULL, [K] [uniqueidentifier] NULL, [L] [uniqueidentifier] NULL, [M] [uniqueidentifier] NULL, [N] [uniqueidentifier] NULL, [O] [uniqueidentifier] NULL, [P] [uniqueidentifier] NULL, [Q] [uniqueidentifier] NULL, [R] [uniqueidentifier] NULL, [S] [uniqueidentifier] NULL, [T] [uniqueidentifier] NULL, [U] [uniqueidentifier] NULL, [V] [uniqueidentifier] NULL, [W] [uniqueidentifier] NULL, [X] [uniqueidentifier] NULL, [Y] [uniqueidentifier] NULL, [Z] [uniqueidentifier] NULL, [AA] [uniqueidentifier] NULL, [AB] [uniqueidentifier] NULL, [AC] [uniqueidentifier] NULL, [AD] [uniqueidentifier] NULL, [AE] [uniqueidentifier] NULL, [AF] [uniqueidentifier] NULL, [AG] [uniqueidentifier] NULL, [AH] [uniqueidentifier] NULL, [AI] [uniqueidentifier] NULL, [AJ] [uniqueidentifier] NULL, [AK] [uniqueidentifier] NULL, [AL] [uniqueidentifier] NULL, [AM] [uniqueidentifier] NULL, [AN] [uniqueidentifier] NULL, [AO] [uniqueidentifier] NULL, [AP] [uniqueidentifier] NULL, [AQ] [uniqueidentifier] NULL, [AR] [uniqueidentifier] NULL ) Make a dummy data set insert into @test2 select Top 50000 ID=ROW_NUMBER()over(order by C.A), NewID() AS A,NewID() AS B,NewID() AS C,NewID() AS D,NewID() AS E,NewID() AS F, NewID() AS G,NewID() AS H,NewID() AS I,NewID() AS J,NewID() AS K,NewID() AS L, NewID() AS M,NewID() AS N,NewID() AS O,NewID() AS P,NewID() AS Q,NewID() AS R, NewID() as S,NewID() AS T,NewID() AS U,NewID() AS V,NewID() AS W,NewID() AS X, NewID() AS Y,NewID() AS Z,NewID() AS AA,NewID() AS AB,NewID() AS AC,NewID() AS AD, NewID() AS AE,NewID() AS AF,NewID() AS AG,NewID() AS AH,NewID() AS AI,NewID() AS AJ, NewID() AS AK,NewID() AS AL,NewID() AS AM,NewID() AS AN,NewID() AS AO,NewID() AS AP, NewID() AS AQ,NewID() AS AR FROM test C cross apply test D cross apply test E cross apply test F cross apply test G cross apply test H cross apply test I cross apply test J cross apply test K cross apply test L cross apply test M cross apply test N cross apply test O cross apply test P cross apply test Q cross apply test R cross apply test S cross apply test T cross apply test U cross apply test V cross apply test W cross apply test X cross apply test Y cross apply test Z Create the tables: Select * into [FirstWideTable] FROM @test2 Select * into [SecondWideTable] FROM @test2 Select * into [ThirdWideTable] FROM @test2 CREATE UNIQUE CLUSTERED INDEX [PK_TEST_A_ID] ON [dbo].[FirstWideTable]([ID] ASC) CREATE UNIQUE CLUSTERED INDEX [PK_TEST_B_ID] ON [dbo].[SecondWideTable]([ID] ASC) CREATE UNIQUE CLUSTERED INDEX [PK_TEST_C_ID] ON [dbo].[ThirdWideTable]([ID] ASC) Run the query a few times allowing statistics data to be created Select a.ID, a.A, a.AB, b.A, b.B, b.C, b.D, c.A, C.B, c.D, c.AA From [FirstWideTable] a LEFT Join [SecondWideTable] b on a.ID=b.ID LEFT Join [ThirdWideTable] c on b.ID=c.ID WHERE a.ID BETWEEN 1 and 50000; Select a.ID, a.A, a.AB, b.A, b.B, b.C, b.D, c.A, C.B, c.D, c.AA From [FirstWideTable] a LEFT Join [SecondWideTable] b on a.ID=b.ID LEFT Join [ThirdWideTable] c on b.ID=c.ID WHERE a.ID BETWEEN 1 and 50000; Select a.ID, a.A, a.AB, b.A, b.B, b.C, b.D, c.A, C.B, c.D, c.AA From [FirstWideTable] a LEFT Join [SecondWideTable] b on a.ID=b.ID LEFT Join [ThirdWideTable] c on b.ID=c.ID WHERE a.ID BETWEEN 1 and 50000; Create the statistics update statistics [FirstWideTable] update statistics [SecondWideTable] update statistics [ThirdWideTable] Grab the results set statistics io,time on Select a.ID, a.A, a.AB, b.A, b.B, b.C, b.D, c.A, C.B, c.D, c.AA From (Select ID, A, AB from [FirstWideTable]) a LEFT Join(Select ID, A, B, C, D from[SecondWideTable]) b on a.ID=b.ID LEFT Join(Select ID, A, B, D, AA from[ThirdWideTable]) c on b.ID=c.ID WHERE a.ID BETWEEN 1 and 50000; set statistics io,time off set statistics io,time on Select a.ID, a.A, a.AB, b.A, b.B, b.C, b.D, c.A, C.B, c.D, c.AA From [FirstWideTable] a LEFT Join [SecondWideTable] b on a.ID=b.ID LEFT Join [ThirdWideTable] c on b.ID=c.ID WHERE a.ID BETWEEN 1 and 50000; set statistics time io,off Showplan: https://www.brentozar.com/pastetheplan/?id=H15IMMYaS
Asked by Jamie (141 rep)
Dec 5, 2019, 01:14 PM
Last activity: Nov 13, 2020, 04:34 AM