我正在使用SQL Server 2012,我想知道我是否写了这句话:
SELECT MyDateTimeColumn
FROM MyTable
WHERE CAST(MyDateTimeColumn AS DATE) = '2014-07-09'
是一种较慢的方式来缩短DATETIME列的时间,我已经搜索了但是我找不到关于这个严格句子的任何内容,我不知道如何显示关于耗时转换/转换来探测它的令人印象深刻的统计数据自己。
答案 0 :(得分:12)
在SQL 2008+中,CAST(foo AS date)
是可以攻击的,还有一些其他的操作。查看sqlfiddle中的执行计划。
<强> SQL Fiddle Demo 强>
答案 1 :(得分:3)
所以,让我们使用Anon的例子。我将其更改为在行号上包含主键,在日期上同时包含非群集索引。
另外,我选择创建随机日期而不是简单的增量更新。
以下是创建测试数据库的代码。
-- Do not save in physical database
USE [tempdb]
GO
-- Drop table
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[test2]') AND type in (N'U'))
DROP TABLE test2
GO
-- Create table
CREATE TABLE test2 (my_num int NOT NULL, my_dt datetime NOT NULL);
GO
-- Add data
INSERT test2
SELECT
TOP 100000
ROW_NUMBER() OVER(ORDER BY (SELECT 1)) as my_num,
DATEADD(minute, RAND() * 500 * ROW_NUMBER() OVER(ORDER BY (SELECT 1)), '2000-01-01') as my_dt
FROM
master.dbo.spt_values t1, master.dbo.spt_values t2
GO
-- Add primary key
ALTER TABLE Test2 ADD CONSTRAINT pk_My_Num PRIMARY KEY (my_num);
GO
-- Add nc index
CREATE INDEX ix_My_Dt ON Test2 (my_dt);
GO
现在,让我们来看看每个解决方案。优点和缺点。
我将使用跟踪标志来查看代数查询分析树以及查询计划。
解决方案1:索引扫描很糟糕,需要将转化应用于每个日期字段。
-- Show output to message screen
DBCC TRACEON(3604)
-- 1 - Not sargable, applies conversion to each date field
SELECT count(*)
FROM Test2
WHERE CONVERT(varchar(10), my_dt, 120) >= '2000-02-01'
AND CONVERT(varchar(10), my_dt, 120) < '2000-02-02'
OPTION (RECOMPILE, QUERYTRACEON 8607)
解决方案2:索引搜索是好的,没有日期字段转换。但是,文化特定日期格式。
-- 2 - Sargable
SELECT count(*)
FROM Test2
WHERE my_dt >= '2000-02-01' AND my_dt < '2000-02-02'
OPTION (RECOMPILE, QUERYTRACEON 8607)
解决方案3:索引搜索哪个好,日期字段没有转换。但是,您必须将日期转换为整数。
-- 3 - Implicit conversion, still Sargable
SELECT COUNT(*) FROM Test2
WHERE my_dt >= 36555 AND my_dt < 36556
OPTION (RECOMPILE, QUERYTRACEON 8607)
解决方案4:索引搜索哪个好,日期字段没有转换。日期采用文化(国家)中立格式。最佳解决方案!
-- 4 - Sargable
SELECT count(*)
FROM Test2
WHERE my_dt >= '20000201' AND my_dt < '20000202'
OPTION (RECOMPILE, QUERYTRACEON 8607);
解决方案5:索引寻求好。将转换应用于每个日期字段,这是不好的。文化特定日期常数。最复杂的查询计划。
-- 5 - Explicit conversion, still sargable
-- applies conversion to each date field
SELECT COUNT(*)
FROM Test2
WHERE CAST(my_dt AS date) >= '2000-02-01'
AND CAST(my_dt AS date) < '2000-02-02'
OPTION (RECOMPILE, QUERYTRACEON 8607);
总之,使用解决方案4,它利用了索引,而不是文化特定的。
使用cast()不是一个好建议。它使用索引,但在比较期间花费了额外的时间来转换每个索引值。
请注意自己,请务必详细解释我的意思。
以下是关于该主题的一些好读物!
参考资料 - 所有关于日期。
http://karaszi.com/the-ultimate-guide-to-the-datetime-datatypes
参考 - 亚伦对日期使用的建议。
https://sqlblog.org/2009/10/16/bad-habits-to-kick-mis-handling-date-range-queries
什么是SARGABLE。
答案 2 :(得分:-1)
使用这种经过验证的方法将日期时间组件“归零”:
select MyDateTimeColumn
from MyTable
where DATEADD(dd, DATEDIFF(dd, 0, MyDateTimeColumn), 0) = CONVERT(date, '07-09-2014', 110)
如果有更快的方法(如上面的技巧),请避免转换为不同的日期类型,并且绝对尽量避免在没有将它们包装在CONVERT()中的情况下使用字符串文字来确保正确解释字符串格式。 / p>
如果您有性能问题并希望强制它使用索引,我建议添加类型为date
的列(用现有列的值减去时间部分填充它),并索引/搜索,或创建一个完成相同的索引视图。