sql >> Base de Datos >  >> RDS >> Sqlserver

datetime vs datetime2 en SQL Server:¿Cuál es la diferencia?

Este artículo explora las principales diferencias entre datetime y fechahora2 tipos de datos en SQL Server.

Si no está seguro de cuál usar, use datetime2 (ver sus ventajas a continuación).

Aquí hay una tabla que describe las diferencias clave entre estos dos tipos.

Característica fechahora fechahora2
Cumple con SQL (ANSI e ISO 8601) No
Intervalo de fechas 1753-01-01 a 9999-12-31 0001-01-01 a 9999-12-31
Intervalo de tiempo 00:00:00 a 23:59:59.997 00:00:00 a 23:59:59.9999999
Longitud de caracteres 19 posiciones mínimo
23 máximo
19 posiciones mínimo
27 máximo
Tamaño de almacenamiento 8 bytes 6 a 8 bytes, dependiendo de la precisión*

* Más 1 byte para almacenar la precisión

Precisión Redondeado a incrementos de .000, .003 o .007 segundos 100 nanosegundos
Precisión fraccionaria de segundo definida por el usuario No
Compensación de zona horaria Ninguno Ninguno
Reconocimiento y preservación de la compensación de zona horaria No No
Consciente del horario de verano No No

Ventajas de 'datetime2'

Como se ve en la tabla anterior, el datetime2 type tiene muchas ventajas sobre datetime , incluyendo:

  • intervalo de fechas más amplio
  • mayor precisión fraccionaria predeterminada
  • precisión opcional especificada por el usuario
  • mayor precisión, incluso cuando se usa el mismo número de lugares decimales que datetime (es decir, 3)
  • menos tamaño de almacenamiento cuando se usa el mismo número de lugares decimales que datetime , pero con mayor precisión*
  • la opción de usar 2 bytes menos de almacenamiento que datetime (aunque con menor precisión)*
  • se alinea con los estándares SQL (ANSI e ISO 8601)

* En algunos casos, un datetime2 value usa un byte adicional para almacenar la precisión, lo que daría como resultado el mismo tamaño de almacenamiento que datetime cuando se usa el mismo número de decimales. Siga leyendo para obtener más información sobre esto.

¿Debería usar 'datetime' o 'datetime2'?

Microsoft recomienda datetime2 sobre fechahora para un nuevo trabajo (y por las mismas razones enumeradas anteriormente).

Por lo tanto, debe usar datetime2 , a menos que tenga una razón específica para no hacerlo (como trabajar con un sistema heredado).

Ejemplo 1:comparación básica

Aquí hay un ejemplo rápido para demostrar la diferencia básica entre datetime y fechahora2 .

DECLARE 
  @thedatetime2 datetime2(7), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5555555';
SET @thedatetime = @thedatetime2;
SELECT 
  @thedatetime2 AS 'datetime2',
  @thedatetime AS 'datetime';

Resultado:

+-----------------------------+-------------------------+
| datetime2                   | datetime                |
|-----------------------------+-------------------------|
| 2025-05-21 10:15:30.5555555 | 2025-05-21 10:15:30.557 |
+-----------------------------+-------------------------+

Aquí, configuro una fecha y hora variable al mismo valor que datetime2 variable. Esto hace que el valor se convierta a datetime y luego podemos usar un SELECT declaración para ver el resultado.

En este caso, el datetime2 variable utiliza una escala de 7, lo que significa 7 decimales. La fechahora value por otro lado, usa solo 3 lugares decimales, y su último dígito fraccionario se redondea hacia arriba (porque este tipo de datos redondea los segundos fraccionarios a incrementos de .000, .003 o .007 segundos).

Ejemplo 2:Uso de 3 decimales

Si reduzco el datetime2 escalar a 3 (para que coincida con dateime ), esto es lo que sucede.

DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5555555';
SET @thedatetime = @thedatetime2;
SELECT 
  @thedatetime2 AS 'datetime2',
  @thedatetime AS 'datetime';

Resultado:

+-------------------------+-------------------------+
| datetime2               | datetime                |
|-------------------------+-------------------------|
| 2025-05-21 10:15:30.556 | 2025-05-21 10:15:30.557 |
+-------------------------+-------------------------+

Entonces el datetime2 el valor también se redondea en este caso. Sin embargo, solo se redondea a 556 – no salta a 557 como la fecha y hora el valor sí.

Por supuesto, la única razón por la que datetime2 el valor se redondea hacia arriba porque el siguiente dígito es 5 o más. Si reducimos el siguiente dígito, no se realiza el redondeo:

DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5554444';
SET @thedatetime = @thedatetime2;
SELECT 
  @thedatetime2 AS 'datetime2',
  @thedatetime AS 'datetime';

Resultado:

+-------------------------+-------------------------+
| datetime2               | datetime                |
|-------------------------+-------------------------|
| 2025-05-21 10:15:30.555 | 2025-05-21 10:15:30.557 |
+-------------------------+-------------------------+

Sin embargo, la fecha y hora el valor continúa siendo redondeado.

Ejemplo 3:configuración de valores a partir de literales de cadena

En los ejemplos anteriores, el dateime el valor se asignó estableciéndolo en el mismo valor que datetime2 valor. Cuando hacemos eso, SQL Server realiza una conversión implícita para que los datos "encajen" en el nuevo tipo de datos.

Sin embargo, si intentamos asignar el mismo literal de cadena a datetime variable que asignamos a datetime2 , obtenemos un error:

DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5554444';
SET @thedatetime = '2025-05-21 10:15:30.5554444';
SELECT 
  @thedatetime2 AS 'datetime2',
  @thedatetime AS 'datetime';

Resultado:

Msg 241, Level 16, State 1, Line 5
Conversion failed when converting date and/or time from character string.

Esto se debe a que datetime solo acepta cadenas literales que tienen 3 o menos fracciones de segundo.

Entonces, para superar este problema, necesitamos reducir la parte fraccionaria a solo 3 (o menos) lugares decimales.

DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5554444';
SET @thedatetime = '2025-05-21 10:15:30.555';
SELECT 
  @thedatetime2 AS 'datetime2',
  @thedatetime AS 'datetime';

Resultado:

+-------------------------+-------------------------+
| datetime2               | datetime                |
|-------------------------+-------------------------|
| 2025-05-21 10:15:30.555 | 2025-05-21 10:15:30.557 |
+-------------------------+-------------------------+

La fechahora2 type no tiene esta limitación, incluso cuando se usa una escala de 3.

Ejemplo 4:tamaño de almacenamiento

La fechahora tipo de datos tiene un tamaño de almacenamiento fijo de 8 bytes.

La fechahora2 por otro lado, puede ser de 6, 7 u 8 bytes, dependiendo de su precisión.

Cuando se usan 3 lugares decimales, datetime2 usa solo 7 bytes, lo que significa que usa menos espacio de almacenamiento que datetime (con más precisión).

Sin embargo, Microsoft afirma que datetime2 type también usa 1 byte adicional para almacenar su precisión. Entonces, en este caso, usaría 8 bytes. Y, por lo tanto, podemos revisar la declaración anterior diciendo que usa 7, 8 o 9 bytes.

Sin embargo, esto probablemente depende de si lo almacenamos en una tabla o en una variable, y si lo convertimos o no en una constante binaria.

Esto es lo que sucede si usamos DATALENGTH() función para devolver el número de bytes utilizados para cada uno de nuestros valores:

DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5554444';
SET @thedatetime = @thedatetime2;
SELECT 
  DATALENGTH(@thedatetime2) AS 'datetime2',
  DATALENGTH(@thedatetime) AS 'datetime';

Resultado

+-------------+------------+
| datetime2   | datetime   |
|-------------+------------|
| 7           | 8          |
+-------------+------------+

Pero si los convertimos a varbinary , obtenemos lo siguiente:

DECLARE 
  @thedatetime2 datetime2(3), 
  @thedatetime datetime;
SET @thedatetime2 = '2025-05-21 10:15:30.5554444';
SET @thedatetime = @thedatetime2;
SELECT 
  DATALENGTH(CONVERT(VARBINARY(16),@thedatetime2)) AS 'datetime2',
  DATALENGTH(CONVERT(VARBINARY(16),@thedatetime)) AS 'datetime';

Resultado

+-------------+------------+
| datetime2   | datetime   |
|-------------+------------|
| 8           | 8          |
+-------------+------------+

Entonces datetime2 usa un byte adicional cuando se convierte a varbinary , lo que lo lleva al mismo tamaño de almacenamiento que datetime .

Sin embargo, el siguiente ejemplo muestra que cuando los datos se almacenan en una columna de base de datos, obtenemos una longitud de 7 bytes para datetime2 y 8 bytes para datetime .

Al almacenar datetime2 valores en una base de datos, la definición de columna incluye la precisión. En este caso, los valores de cada fila no necesitan el byte adicional para almacenar la precisión, y podemos decir que datetime2 usa menos espacio de almacenamiento que datetime cuando se utiliza el mismo número de fracciones de segundo.

Ejemplo 5:tamaño de almacenamiento para datos almacenados

En este ejemplo, creo una base de datos y uso COL_LENGTH para devolver la longitud de cada columna, en bytes. Luego inserto un datetime2 y fechahora valor en él y use DBCC PAGE() para encontrar la longitud de los datos reales en el archivo de página. Esto nos muestra el espacio de almacenamiento que utiliza cada tipo de datos cuando se almacena en una base de datos.

Crear una base de datos:

CREATE DATABASE CompareTypes;

Crear una tabla:

USE CompareTypes;

CREATE TABLE Datetime2vsDatetime (
    TheDateTime datetime,
    TheDateTime2 datetime2(3)
    );

En este caso, creo dos columnas:una es datetime columna y la otra es una datetime2 columna.

Compruebe la longitud de la columna

Compruebe la longitud (en bytes) de cada columna:

SELECT 
  COL_LENGTH ( 'dbo.Datetime2vsDatetime' , 'TheDateTime2' ) AS 'datetime2',
  COL_LENGTH ( 'dbo.Datetime2vsDatetime' , 'TheDateTime' ) AS 'datetime';  

Resultado:

+-------------+------------+
| datetime2   | datetime   |
|-------------+------------|
| 7           | 8          |
+-------------+------------+

Entonces vemos que el datetime2 la columna tiene una longitud de 7 bytes, en comparación con datetime longitud de 8 bytes.

Insertar datos

Ahora veamos el tamaño de almacenamiento de los valores reales de fecha y hora cuando se almacenan en SQL Server. Podemos usar DBCC PAGE() para inspeccionar la página real en el archivo de datos.

Pero primero, necesitamos insertar datos en nuestras columnas.

Insertar datos:

DECLARE @thedatetime2 datetime2 = '2025-05-21 10:15:30.5554444';
INSERT INTO Datetime2vsDatetime ( TheDateTime, TheDateTime2 )
SELECT @thedatetime2, @thedatetime2;

Selecciona los datos (solo para comprobarlo):

SELECT * FROM Datetime2vsDatetime;

Resultado:

+-------------------------+-------------------------+
| TheDateTime             | TheDateTime2            |
|-------------------------+-------------------------|
| 2025-05-21 10:15:30.557 | 2025-05-21 10:15:30.555 |
+-------------------------+-------------------------+

Uso de la PÁGINA DBCC()

Aquí es donde usamos DBCC PAGE() para inspeccionar la página real en el archivo de datos.

Primero, usaremos DBCC IND() para encontrar el PagePID:

DBCC IND('CompareTypes', 'dbo.Datetime2vsDatetime', 0);

Resultado (usando salida vertical):

-[ RECORD 1 ]-------------------------
PageFID         | 1
PagePID         | 307
IAMFID          | NULL
IAMPID          | NULL
ObjectID        | 885578193
IndexID         | 0
PartitionNumber | 1
PartitionID     | 72057594042974208
iam_chain_type  | In-row data
PageType        | 10
IndexLevel      | NULL
NextPageFID     | 0
NextPagePID     | 0
PrevPageFID     | 0
PrevPagePID     | 0
-[ RECORD 2 ]-------------------------
PageFID         | 1
PagePID         | 320
IAMFID          | 1
IAMPID          | 307
ObjectID        | 885578193
IndexID         | 0
PartitionNumber | 1
PartitionID     | 72057594042974208
iam_chain_type  | In-row data
PageType        | 1
IndexLevel      | 0
NextPageFID     | 0
NextPagePID     | 0
PrevPageFID     | 0
PrevPagePID     | 0

Esto devuelve dos registros. Estamos interesados ​​en el PageType de 1 (el segundo registro). Queremos el PagePID de ese registro. En este caso, el PagePID es 320 .

Ahora podemos tomar ese PagePID y usarlo en lo siguiente:

DBCC TRACEON(3604, -1);
DBCC PAGE(CompareTypes, 1, 320, 3);

Esto produce una gran cantidad de datos, pero estamos interesados ​​principalmente en la siguiente parte:

Slot 0 Column 1 Offset 0x4 Length 8 Length (physical) 8

TheDateTime = 2025-05-21 10:15:30.557                                    

Slot 0 Column 2 Offset 0xc Length 7 Length (physical) 7

TheDateTime2 = 2025-05-21 10:15:30.555                                    

Esto muestra que datetime usa una longitud de 8 bytes y datetime2(3) utiliza 7 bytes cuando se almacena en una base de datos.

Entonces esto refuerza el caso para usar datetime2 sobre fechahora al diseñar nuevas bases de datos, especialmente si el tamaño del almacenamiento es una preocupación.