将日期时间值填充到 datetime2 列中

GaT*_*mas 6 sql-server datetime

今天在代码审查中看到这样的说法:

ALTER TABLE dbo.MyTable ADD CreateDate DATETIME2(0) NOT NULL DEFAULT GETUTCDATE()
Run Code Online (Sandbox Code Playgroud)

GETUTCDATE() 函数返回 a datetime,然后将其填充到datetime2列中。

这两种类型的不同有什么意义吗?使用 SYSUTCDATETIME() 创建datetime2值会更好吗?

Joh*_* N. 6

您的列CreateDate用于DATETIME2(0)日期定义。从表中检索值时,插入SYSUTCDATETIME()或没有区别。GETUTCDATE()

让我们以您的表定义为例:

CREATE TABLE dbo.MyTable 
  (
  ID int IDENTITY (1,1),
  CreateDate DATETIME2(0) NOT NULL DEFAULT GETUTCDATE(),
  CreateDateSYS DATETIME2(0) NOT NULL DEFAULT SYSUTCDATETIME()
  );
Run Code Online (Sandbox Code Playgroud)

然后我们向表中添加一些值:

INSERT INTO MyTable (CreateDate, CreateDateSYS) 
VALUES 
  (GETUTCDATE(),GETUTCDATE()),
  (SYSUTCDATETIME(), SYSUTCDATETIME()),
  ('2023-03-30 07:16:45.1','2023-03-30 07:16:45.1'),
  ('2023-03-30 07:16:45.12','2023-03-30 07:16:45.12'),
  ('2023-03-30 07:16:45.123','2023-03-30 07:16:45.123'),
  ('2023-03-30 07:16:45.1234','2023-03-30 07:16:45.1234'),
  ('2023-03-30 07:16:45.12345','2023-03-30 07:16:45.12345')
  ;
Run Code Online (Sandbox Code Playgroud)

SYSUTCDATETIME()让我们看看和 之间是否有区别GETUTCDATE()

SELECT * FROM MyTable;
Run Code Online (Sandbox Code Playgroud)
ID 创建日期 创建日期系统
1 2023-03-30 07:21:12 2023-03-30 07:21:12
2 2023-03-30 07:21:12 2023-03-30 07:21:12
3 2023-03-30 07:16:45 2023-03-30 07:16:45
4 2023-03-30 07:16:45 2023-03-30 07:16:45
5 2023-03-30 07:16:45 2023-03-30 07:16:45
6 2023-03-30 07:16:45 2023-03-30 07:16:45
7 2023-03-30 07:16:45 2023-03-30 07:16:45

正如您所看到的,插入GETUTCDATE()SYSUTCDATETIME()对存储的内容没有影响。这是因为列(如您的示例中)是使用DATETIME2(0)默认精度定义的。

DATETIME2(7)如果我们创建一个包含使用(精度更高)的列并插入不同值的表,那么我们会收到以下结果。

首先我们创建表:

CREATE TABLE dbo.MyTableFixed 
  (
  ID int IDENTITY (1,1),
  CreateDate DATETIME2(7) NOT NULL DEFAULT GETUTCDATE(),
  CreateDateSYS DATETIME2(7) NOT NULL DEFAULT SYSUTCDATETIME()
  );
Run Code Online (Sandbox Code Playgroud)

然后我们插入一些具有不同精度的日期时间值:

INSERT INTO MyTableFixed (CreateDate, CreateDateSYS) 
VALUES 
  (GETUTCDATE(),GETUTCDATE()),
  (SYSUTCDATETIME(), SYSUTCDATETIME()),
  ('2023-03-30 07:16:45.1','2023-03-30 07:16:45.1'),
  ('2023-03-30 07:16:45.12','2023-03-30 07:16:45.12'),
  ('2023-03-30 07:16:45.123','2023-03-30 07:16:45.123'),
  ('2023-03-30 07:16:45.1234','2023-03-30 07:16:45.1234'),
  ('2023-03-30 07:16:45.12345','2023-03-30 07:16:45.12345')
  ;
Run Code Online (Sandbox Code Playgroud)

然后我们从表中选择值:

SELECT * FROM MyTableFixed;
Run Code Online (Sandbox Code Playgroud)

返回以下结果:

ID 创建日期 创建日期系统
1 2023-03-30 07:21:11.5500000 2023-03-30 07:21:11.5500000
2 2023-03-30 07:21:11.5508485 2023-03-30 07:21:11.5508485
3 2023-03-30 07:16:45.1000000 2023-03-30 07:16:45.1000000
4 2023-03-30 07:16:45.1200000 2023-03-30 07:16:45.1200000
5 2023-03-30 07:16:45.1230000 2023-03-30 07:16:45.1230000
6 2023-03-30 07:16:45.1234000 2023-03-30 07:16:45.1234000
7 2023-03-30 07:16:45.1234500 2023-03-30 07:16:45.1234500

注意:此答案中使用的示例可以在db<>fiddle
上运行和测试

回答您的问题

这两种类型的不同有什么意义吗?

CreateDate在您的情况下不是,因为您使用低精度类型定义了列DATETIME2(0)

SYSUTCDATETIME()用来创造价值会更好吗datetime2

在您的情况下不是,因为即使您将创建一个DATETIME2高精度的值,您也会将其存储在DATETIME2(0)精度较低的列中。

如果您的问题涉及插入数据时可能对性能产生的影响...
...那么当某些值传递到列时,可能会产生轻微的开销。这是由于发生了隐式转换。这可以从执行计划中获得。

  • 将日期插入到DATETIME2(0)定义的列中时,您可能会观察到

    CONVERT_IMPLICIT(datetime2(0),[@1],0)              -- actual value 
    CONVERT_IMPLICIT(datetime2(0),getutcdate(),0)      -- getutcdate()
    CONVERT_IMPLICIT(datetime2(0),sysutcdatetime(),0)  -- sysutcdatetime()
    
    Run Code Online (Sandbox Code Playgroud)
  • 将日期插入到DATETIME2(7)定义的列中时,您可能会观察到

    CONVERT_IMPLICIT(datetime2(7),[@1],0)              -- actual value 
    CONVERT_IMPLICIT(datetime2(7),getutcdate(),0)      -- getutcdate()
    
    Run Code Online (Sandbox Code Playgroud)
  • sysutcdatetime()插入到定义的列时,您不会观察到隐式转换DATETIME2(7)。这是因为不必将值从一种日期时间格式转换为另一种日期时间格式。SYSUTCDATETIME()将返回一个真正的DATETIME2(7)格式化值。

    Scalar Operator(sysutcdatetime())                  -- sysutcdatetime()
    
    Run Code Online (Sandbox Code Playgroud)

以下是包含转换的执行计划的屏幕截图CONVERT_IMPLICIT

包含 CONVERT_IMPLICIT 的执行计划属性的屏幕截图

可能的解决方案

如果您要使用存储更高精度值的ALTER列,那么您可以从切换到.DATETIME2(7)DATETIME2SYSUTCDATETIME()

如果您不需要这么高的精度,请考虑使用较低的值,因为这将占用表中更少的存储空间:

Storage Size 6 bytes for precision less than 3.
             7 bytes for precision 3 or 4.
             All other precision require 8 bytes.2
Run Code Online (Sandbox Code Playgroud)

参考资料