SQL Server 2008 Datetime Cast 成 Date 類型可使用索引(轉載)

好久沒寫blog,不是懶,實在是最近我這的訪問速度很差,用firefox常常上傳不了圖片 .......

今天無心發現了SQL Server 2008 Datetime Cast 成 Date 類型可使用索引,分享一下:sql

測試環境:oop

複製代碼
USE TEMPDB
GO

CREATE TABLE TB
(
ID INT IDENTITY(1,1) PRIMARY KEY,
NAME VARCHAR(200),
OPTIME DATETIME DEFAULT GETDATE()
)
GO
DECLARE @I INT = 1
WHILE @I<10001
BEGIN
    INSERT INTO TB(NAME) SELECT 'A'+LTRIM(@I)
    SET @I=@I+1
END
GO
INSERT INTO TB(NAME,OPTIME) SELECT 'A10001','2010-05-27 16:25:20.117'
GO
CREATE INDEX IX_OPTIME ON TB(OPTIME)
GO
複製代碼


由上面的T-sql能夠看出,若是咱們查 2010年5月27的數據,應該只有一條。
爲了更明顯說明如下四種寫法的區別,打開IO/執行計劃開關,而且選中執行結果包含實際執行計劃測試

SET STATISTICS IO ON
SET STATISTICS PROFILE ON 


如下是四種寫法:spa

第一種寫法:firefox

SELECT * FROM TB WHERE CONVERT(VARCHAR(10),OPTIME,120)='2010-05-27'

消息結果:code

  (1 row(s) affected)
  表 'TB'。掃描計數 1,邏輯讀取 40 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。 blog

執行計劃:索引

    
經過上面的執行計劃,能夠看到是彙集索引掃描,會掃描全部的索引葉,這不是咱們但願的,它沒法有效利用索引.
圖片

第二種寫法:it

SELECT * FROM TB WHERE LTRIM(YEAR(OPTIME))+'-'+LTRIM(MONTH(OPTIME))+'-'+LTRIM(DAY(OPTIME))='2010-5-27'

消息結果: 

  (1 row(s) affected)
  表 'TB'。掃描計數 1,邏輯讀取 40 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。 

執行計劃:

 

     

 一樣,第二種方法和第一種同樣,一樣低效.

第三種寫法:

SELECT * FROM TB WHERE OPTIME BETWEEN '2010-05-27 00:00:00.000' AND '2010-05-27 23:59:59.999' 

消息結果:
  (1 row(s) affected)
  表 'TB'。掃描計數 1,邏輯讀取 4 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。
執行計劃:

    
由上面的結果和執行計劃能夠看出,這個寫法是有效的利用了非彙集索引,效率很高.但須要本身補充好這一天的範圍.'00:00:00.000' AND '23:59:59.999' .


第四種寫法:

SELECT * FROM TB WHERE CAST(OPTIME AS DATE)='2010-05-27'

消息結果:
  (1 row(s) affected)
  表 'TB'。掃描計數 1,邏輯讀取 4 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次。

執行計劃:
     
從上面的結果咱們能夠看到,這種寫法雖然用了cast轉變了數據類型,但依然能夠有效使用索引,讀取的page數是4,與第三種寫法相同,一樣高效.  

經過查看執行計劃StmtText字段發現:
SELECT * FROM [TB] WHERE CONVERT([date],[OPTIME],0)=@1
  |--Nested Loops(Inner Join, OUTER REFERENCES:([tempdb].[dbo].[TB].[ID]))
       |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1006], [Expr1007], [Expr1005]))
       |    |--Compute Scalar(DEFINE:(([Expr1006],[Expr1007],[Expr1005])=GetRangeThroughConvert('2010-05-27','2010-05-27',(62))))
       |    |    |--Constant Scan
       |    |--Index Seek(OBJECT:([tempdb].[dbo].[TB].[IX_OPTIME]), SEEK:([tempdb].[dbo].[TB].[OPTIME] > [Expr1006] AND [tempdb].[dbo].[TB].[OPTIME] < [Expr1007]),  WHERE:(CONVERT(date,[tempdb].[dbo].[TB].[OPTIME],0)='2010-05-27') ORDERED FORWARD)
       |--Clustered Index Seek(OBJECT:([tempdb].[dbo].[TB].[PK__TB__3214EC27753864A1]), SEEK:([tempdb].[dbo].[TB].[ID]=[tempdb].[dbo].[TB].[ID]) LOOKUP ORDERED FORWARD)

執行計劃將'2010-05-27'獲得了Expr1006Expr1007,而後再走索引查找:OPTIME>Expr1006 and OPTIME<Expr1007.

那麼Expr1006Expr1007是否就是'2010-05-26 23:59:59.998' 和'2010-05-28 00:00:00.000' 呢? 我不知道,可是我看像.. 你以爲呢?

    

 若有錯誤,請指正,謝謝.

相關文章
相關標籤/搜索