【问题标题】:SQL Fastest way to compare two dates (non standard varchar format and datetime)SQL 比较两个日期的最快方法(非标准 varchar 格式和日期时间)
【发布时间】:2010-09-23 19:03:34
【问题描述】:

我有两个“日期”字段需要加入。

第一个是yyyy-mm-dd hh:mm:ss格式的普通日期时间

第二个是红头步子格式的varchar(8)mmddyyyy

现在这很痛苦,因为没有简单的方法可以转换为相应的类型。有一个内置格式是 yyyymmdd,但它与 varchar 格式不匹配。

我可以看到两条路径:

declare @normal_date as datetime;
declare @hated_date as varchar(8);

set @normal_date='1974-11-01 00:00:00.000'
set @hated_date='11011974'

--cast to date time with string splits
select @normal_date
where CONVERT(datetime, RIGHT(@hated_date,4)+LEFT(@hated_date,2)+SUBSTRING(@hated_date,3,2))=@normal_date

--convert normal date to ackward format
select @normal_date
      where REPLACE(CONVERT(varchar(10),@normal_date,101), '/','')=@hated_date

哪个更好?还是有更好的办法?

已编辑以显示费用

--Operator cost (39%)
CONVERT(datetime, RIGHT(@hated_date,4)+LEFT(@hated_date,2)+SUBSTRING(@hated_date,3,2))=@normal_date

--Operator cost (57%)
REPLACE(CONVERT(varchar(10),@normal_date,101), '/','')=@hated_date

--Operator cost (46%)
cast(stuff(stuff(@hated_date, 3,0, '/'),6,0,'/') as datetime)=@normal_date

--Operator cost (47%)
RIGHT(@hated_date, 4) + LEFT(@hated_date, 4)=@normal_date

【问题讨论】:

  • 执行计划中的操作员成本没有意义。您需要使用SET STATISTICS IO ON 运行每个一百万次左右并进行比较。我想你会发现其中大部分都差不多。

标签: sql sql-server performance sql-server-2008


【解决方案1】:

这是 yyyymmdd 没有?

RIGHT(@hated_date, 4) + LEFT(@hated_date, 4)

所以,你的脚本变成了

declare @normal_date as datetime;
declare @hated_date as varchar(8);

set @normal_date='1974-11-01 00:00:00.000'
set @hated_date='11011974'

--SELECT @hated_date = RIGHT(@hated_date, 4) + LEFT(@hated_date, 4))

select 'hurrah' WHERE @normal_date = RIGHT(@hated_date, 4) + LEFT(@hated_date, 4)

【讨论】:

  • @Denis Valeev:你是在一张桌子上测试它还是只在上面一行测试它?
【解决方案2】:

另一种方法是这样的:

MONTH(@normal_date)*1000000 + DAY(@normal_date)*10000 + YEAR(@normal_date)
=
CAST(@hated_date AS INT)

还有一件事:比较实际执行成本比依赖优化器的估计更精确。

【讨论】:

  • 根据我的结果,您的方法似乎是最快的。这当然有些偏颇,这需要在 Nix 的生产服务器上得到证明才能最终决定。
  • 我不会说“更精确”,因为在这种情况下执行计划成本几乎没有意义。我会说“唯一的方法”。
【解决方案3】:

试试这个:

select cast(stuff(stuff('11011974', 3,0, '/'),6,0,'/') as datetime)

更新

【讨论】:

  • 您可能想在此查询之前添加set dateformat mdy
  • 这行得通,但它的性能和其他的一样。我会说“讨厌”的格式是记录较少的格式。
  • @Nix 你如何衡量不同方法的性能?在生产环境中运行?
  • 我正在使用解释计划.. 我正在查看与上述类似的脚本,以及实际的“生产”查询计划我毫不怀疑有一些非常需要的索引这些表。我只想尽量减少运营成本
  • @Nix SQL Server 没有解释计划。它有执行计划。
【解决方案4】:

建议您将列修复为 datetime 或将 datetime 列添加到表中并转换数据,这样您只需在输入数据时进行一次转换(当然对于现有数据一次)这可能甚至可能是一个计算列。这不是您希望在 select 语句中做的事情。如有必要,创建一个包含两个甲酸盐中每个可能日期的日期转换表,如果该表无法更改,则加入该表。

您可能还需要检查以确保其中没有无效日期,这总是有可能将日期存储在日期时间以外的数据类型中。

【讨论】:

  • If necessary create a dateconversion table with every opossible date in both formates and join to it if the table can't be changed. 你确定这会比简单的字符串操作更快吗?
  • 如果它被索引,我希望它会更快,但你必须测试。这可能取决于所涉及的记录数量。转换通常很慢。但是修复数据库结构是最好的选择。它使进行比较变得容易,使输入不是日期的数据变得不可能,并且使您在需要进行数据数学运算的地方也可以更轻松地进行其他查询。
  • 无法更改表格。我很想...不知道你为什么要使用格式错误的“varchar”日期。
猜你喜欢
  • 2016-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-10
相关资源
最近更新 更多