SQL Server 2008 Datetime Cast 成 Date 类型可以使用索引(转载)
很久没写blog,不是懒,实在是最近我这的访问速度不好,用firefox经常上传不了图片 .......
今天无意发现了SQL Server 2008 Datetime Cast 成 Date 类型可以使用索引,分享一下:
测试环境:
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 PROFILE ON
以下是四种写法:
第一种写法:
消息结果:
(1 row(s) affected)
表 'TB'。扫描计数 1,逻辑读取 40 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
执行计划:
通过上面的执行计划,可以看到是聚集索引扫描,会扫描所有的索引叶,这不是我们希望的,它无法有效利用索引.
第二种写法:
消息结果:
(1 row(s) affected)
表 'TB'。扫描计数 1,逻辑读取 40 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
执行计划:
同样,第二种方法和第一种一样,同样低效.
第三种写法:
消息结果:
(1 row(s) affected)
表 'TB'。扫描计数 1,逻辑读取 4 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
执行计划:
由上面的结果和执行计划可以看出,这个写法是有效的利用了非聚集索引,效率很高.但需要自己补充好这一天的范围.即'00:00:00.000' AND '23:59:59.999' .
第四种写法:
消息结果:
(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'得到了Expr1006和Expr1007,然后再走索引查找:OPTIME>Expr1006 and OPTIME<Expr1007.
那么Expr1006和Expr1007是否就是'2010-05-26 23:59:59.998' 和'2010-05-28 00:00:00.000' 呢? 我不知道,但是我看像.. 你觉得呢?
如有错误,请指正,谢谢.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?