Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
PSamsig
Constraint Violating Yak Guru
384 Posts |
Posted - 2011-03-18 : 19:05:27
|
Sorry if this has already been debated to death, but I have been out of the loop here for a while.Fresh home from DevWeek/SQL Server DevCon in London this past week, i had my head fille with lots of cool stuff, I hardly have had the time to process, but for one in particular.I attended a talk about some of the cool new features in SQL Server 2008 (as I already said, I am a bit behind), one of them being the new date type. Nothing much groundbreaking about that, but for:WHERE CONVERT(date, some_indexed_datetime_col) = '20110318' is sargable, and even worse, it performes bettet than:WHERE some_indexed_datetime_col >= '20110318' AND some_indexed_datetime_col < '20110319' which means that I will start using it when opertunity arise, which again means someone will read my code and think that all kinds of non-sargable nonses is fine as well ... and the world ends in a puff of smoke and an evil laughter!-- If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime. |
|
Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)
7020 Posts |
Posted - 2011-03-18 : 23:43:56
|
Interesting, but have you actually tested that it performs better?I did, and what I saw was that the first query plan transformed internally into a query in the form of:where indexed_datetime_col > @StartDate and indexed_datetime_col < @EndDate and actually had a query plan identical to the second, except for the computation of @StartDate and @EndDate in the first query.Also, the execution statistics were identical for both:Table 'T_DATE'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.I would say that they perform equally well, but see no reason to believe that the first performs better.-- Test codeCREATE table T_DATE (DT datetime not null primary key clustered )-- Load table with 109,573 datesinsert into T_DATE(DT)select date from dbo.F_TABLE_DATE('19000101','21991231') ORDER BY dateselect * from T_DATE a WHERE CONVERT(date,a.DT) = '20110318'select * from T_DATE a WHERE a.DT >= '20110318' and a.DT < '20110319' CODO ERGO SUM |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2011-03-19 : 01:45:26
|
There is a little overhead for first queryStmtText |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1005], [Expr1006], [Expr1004])) |--Compute Scalar(DEFINE:(([Expr1005],[Expr1006],[Expr1004])=GetRangeThroughConvert(CONVERT_IMPLICIT(date,[@1],0),CONVERT_IMPLICIT(date,[@1],0),(62)))) | |--Constant Scan |--Clustered Index Seek(OBJECT:([tempdb].[dbo].[T_DATE].[PK__T_DATE__3214621725C12FCC] AS [a]), SEEK:([a].[DT] > [Expr1005] AND [a].[DT] < [Expr1006]), WHERE:(CONVERT(date,[tempdb].[dbo].[T_DATE].[DT] as [a].[DT],0)=CONVERT_IMPLICIT(date,[@1],0)) ORDERED FORWARD) And the second queryStmtText |--Clustered Index Seek(OBJECT:([tempdb].[dbo].[T_DATE].[PK__T_DATE__3214621725C12FCC] AS [a]), SEEK:([a].[DT] >= CONVERT_IMPLICIT(datetime,[@1],0) AND [a].[DT] < CONVERT_IMPLICIT(datetime,[@2],0)) ORDERED FORWARD) There seem to be some optimization done for the date datatype but still more work is needed. N 56°04'39.26"E 12°55'05.63" |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
|
PSamsig
Constraint Violating Yak Guru
384 Posts |
Posted - 2011-03-23 : 15:19:59
|
I have been wating for the axamples from the talk to be published, and I can reproduce that date type query optimation is slightly superior to the 'old' method.use northwindgo-- index seekselect orderid, customerid, orderdate from orders where orderdate >= '19970324' and OrderDate < '19970325';-- index seek, cheaper plan than first one select orderid, customerid, orderdate from orders where convert(date, orderdate) = '19970324'; Gives a execute ratio of 53% for the first and 47% for the second, it is correct though, that the execution plan for the second one seems more complicated (makes a constant table on which it join through), but unless my SSMS lies, it is faster.Apart for the oddness of being (slightly) faster, what troubles me is that it is now much more difficult to teach people about what constructs is sargable and what is not.The session I got this from was by Bob Beauchemin, and I know that in a session I didn't have time to attend, Itzik Ben-Gan recomended this as well, in case anyone in familiar with either.-- If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime. |
|
|
Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)
7020 Posts |
Posted - 2011-03-23 : 16:13:06
|
quote: Originally posted by PSamsig I have been wating for the axamples from the talk to be published, and I can reproduce that date type query optimation is slightly superior to the 'old' method.use northwindgo-- index seekselect orderid, customerid, orderdate from orders where orderdate >= '19970324' and OrderDate < '19970325';-- index seek, cheaper plan than first one select orderid, customerid, orderdate from orders where convert(date, orderdate) = '19970324'; Gives a execute ratio of 53% for the first and 47% for the second, it is correct though, that the execution plan for the second one seems more complicated (makes a constant table on which it join through), but unless my SSMS lies, it is faster.Apart for the oddness of being (slightly) faster, what troubles me is that it is now much more difficult to teach people about what constructs is sargable and what is not.The session I got this from was by Bob Beauchemin, and I know that in a session I did have time to attend, Itzik Ben-Gan recomended this as well, in case anyone in familiar with either.-- If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime.
Your results only have the plan, not the execution statistics for each query.Example:Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.CODO ERGO SUM |
|
|
PSamsig
Constraint Violating Yak Guru
384 Posts |
Posted - 2011-03-23 : 17:12:11
|
Let me modify your own test exampel, just to make it slightly more realistic:CREATE TABLE dbo.T_DATE( ID int IDENTITY(1,1) NOT NULL, DT datetime NOT NULL, Filler varchar(50) NULL, CONSTRAINT PK_T_DATE PRIMARY KEY CLUSTERED (ID))GO-- Load table with 109,573 datesinsert into T_DATE(DT)select date from dbo.F_TABLE_DATE('19000101','21991231')GOCREATE NONCLUSTERED INDEX IX_T_DATE_DT ON dbo.T_DATE (DT)GOSET STATISTICS IO ON GOselect * from T_DATE a WHERE a.DT >= '20110318' and a.DT < '20110319'select * from T_DATE a WHERE CONVERT(date,a.DT) = '20110318' the IO statistics is excatly the sameTable 'T_DATE'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. but the excecution ratio is 56%/44%, not bad if you ask me.-- If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime. |
|
|
Michael Valentine Jones
Yak DBA Kernel (pronounced Colonel)
7020 Posts |
Posted - 2011-03-23 : 17:24:49
|
The execution stats are the only thing that really count.If it reads the same number of pages with the same cpu, then it doesn't really matter about the ratio in the query plan display.The difference in the ratio is more about SQL Server getting lost when creating the estimate.CODO ERGO SUM |
|
|
PSamsig
Constraint Violating Yak Guru
384 Posts |
Posted - 2011-03-24 : 03:53:16
|
To make a difference we need even more data:-- Waste of time until we are done expanding tableDROP INDEX dbo.T_DATE.IX_T_DATE_DTGO-- Make our table a desent sizeINSERT T_DATE (DT) SELECT DT FROM T_DATE -- 2INSERT T_DATE (DT) SELECT DT FROM T_DATE -- 4INSERT T_DATE (DT) SELECT DT FROM T_DATE -- 8INSERT T_DATE (DT) SELECT DT FROM T_DATE -- 16INSERT T_DATE (DT) SELECT DT FROM T_DATE -- 32INSERT T_DATE (DT) SELECT DT FROM T_DATE -- 64INSERT T_DATE (DT) SELECT DT FROM T_DATE --128INSERT T_DATE (DT) SELECT DT FROM T_DATE --256GO-- Lets add some random time partUPDATE T_DATE SET DT = DATEADD(SECOND, abs(checksum(newid())) % (24 * 60 * 60), DT)GO-- Building the index againCREATE NONCLUSTERED INDEX IX_T_DATE_DT ON dbo.T_DATE (DT ASC)GOSET STATISTICS IO ONGOselect * from T_DATE a WHERE a.DT >= '20110318' and a.DT < '20110319'select * from T_DATE a WHERE CONVERT(date,a.DT) = '20110318' and here comes the interesting part:(256 row(s) affected)Table 'T_DATE'. Scan count 1, logical reads 797, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.(256 row(s) affected)Table 'T_DATE'. Scan count 1, logical reads 772, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. In case you wonder, it is the added time part that makes the difference, without it you get the same number of logical reads.The query ratio is now 99%/1%, which is odd, but it is still to little data to makes some real time mesures.-- If you give someone a program, you will frustrate them for a day; if you teach them how to program, you will frustrate them for a lifetime. |
|
|
|
|
|
|
|