zoukankan      html  css  js  c++  java
  • SQL Server 2008 Datetime Cast 成 Date 类型可以使用索引(转载)

    很久没写blog,不是懒,实在是最近我这的访问速度不好,用firefox经常上传不了图片 .......

    今天无意发现了SQL Server 2008 Datetime Cast 成 Date 类型可以使用索引,分享一下:

    测试环境:

    复制代码
    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 


    以下是四种写法:

    第一种写法:

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

    消息结果:

      (1 row(s) affected)
      表 'TB'。扫描计数 1,逻辑读取 40 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。 

    执行计划:

        
    通过上面的执行计划,可以看到是聚集索引扫描,会扫描所有的索引叶,这不是我们希望的,它无法有效利用索引.

    第二种写法:

    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' 呢? 我不知道,但是我看像.. 你觉得呢?

        

     如有错误,请指正,谢谢.

  • 相关阅读:
    oracle基础~ash报告管理
    django基础-bootstarp
    django基础~admin入门
    django基础~jquery交互
    oracle基础~RAC-grid搭建
    Oracle基础~RAC搭建准备二
    oracle基础~RAC搭建准备一
    oracle基础~补丁安装
    环境准备、框架认识、新建maven项目和配置tomcat
    python线程问题、深浅拷贝、属性动态设置
  • 原文地址:https://www.cnblogs.com/qanholas/p/4642282.html
Copyright © 2011-2022 走看看