SQL Server 2008 y posteriores
En SQL Server 2008 y posteriores, por supuesto, la forma más rápida es Convert(date, @date)
. Esto se puede devolver a datetime
o datetime2
si es necesario.
¿Qué es realmente mejor en SQL Server 2005 y versiones anteriores?
He visto afirmaciones inconsistentes sobre lo que es más rápido para truncar el tiempo de una fecha en SQL Server, y algunas personas incluso dijeron que hicieron pruebas, pero mi experiencia ha sido diferente. Así que hagamos algunas pruebas más estrictas y dejemos que todos tengan el guión para que, si cometo algún error, la gente pueda corregirme.
Las conversiones flotantes no son precisas
Primero, me mantendría alejado de convertir datetime
a float
, porque no se convierte correctamente. Puede salirse con la suya haciendo la eliminación del tiempo con precisión, pero creo que es una mala idea usarlo porque les comunica implícitamente a los desarrolladores que esta es una operación segura y no lo es . Echar un vistazo:
declare @d datetime;
set @d = '2010-09-12 00:00:00.003';
select Convert(datetime, Convert(float, @d));
Esto no es algo que debamos enseñar a las personas en nuestro código o en nuestros ejemplos en línea.
Además, ¡ni siquiera es la forma más rápida!
Prueba: prueba de rendimiento
Si desea realizar algunas pruebas usted mismo para ver cómo se comparan realmente los diferentes métodos, necesitará este script de configuración para ejecutar las pruebas más abajo:
create table AllDay (Tm datetime NOT NULL CONSTRAINT PK_AllDay PRIMARY KEY CLUSTERED);
declare @d datetime;
set @d = DateDiff(Day, 0, GetDate());
insert AllDay select @d;
while @@ROWCOUNT != 0
insert AllDay
select * from (
select Tm =
DateAdd(ms, (select Max(DateDiff(ms, @d, Tm)) from AllDay) + 3, Tm)
from AllDay
) X
where Tm < DateAdd(Day, 1, @d);
exec sp_spaceused AllDay;
Tenga en cuenta que esto crea una tabla de 427,57 MB en su base de datos y tardará entre 15 y 30 minutos en ejecutarse. Si su base de datos es pequeña y está configurada para un crecimiento del 10%, tomará más tiempo que si primero tiene un tamaño lo suficientemente grande.
Ahora para el script de prueba de rendimiento real. Tenga en cuenta que tiene el propósito de no devolver las filas al cliente, ya que esto es muy caro en 26 millones de filas y ocultaría las diferencias de rendimiento entre los métodos.
Resultados de desempeño
set statistics time on;
GO
declare
@dd date,
@d datetime,
@di int,
@df float,
@dv varchar(10);
select @d = CONVERT(date, Tm) from AllDay;
select @d = CAST(Tm - 0.50000004 AS int) from AllDay;
select @d = DATEDIFF(DAY, 0, Tm) from AllDay;
select @d = FLOOR(CAST(Tm as float)) from AllDay;
select @d = CONVERT(VARCHAR(8), Tm, 112) from AllDay;
select @d = CONVERT(CHAR(8), Tm, 112) from AllDay;
select @d = CONVERT(VARCHAR(10), Tm, 101) from AllDay;
select @dd = Tm from AllDay;
select @di = CAST(Tm - 0.50000004 AS int) from AllDay;
select @di = DATEDIFF(DAY, 0, Tm) from AllDay;
select @df = FLOOR(CAST(Tm as float)) from AllDay;
select @dv = CONVERT(VARCHAR(8), Tm, 112) from AllDay;
select @dv = CONVERT(CHAR(8), Tm, 112) from AllDay;
select @dv = CONVERT(VARCHAR(10), Tm, 101) from AllDay;
GO
set statistics time off;
Algunos análisis divagantes
Algunas notas sobre esto. En primer lugar, si solo realiza un GROUP BY o una comparación, no es necesario volver a convertir a datetime
. Por lo tanto, puede ahorrar algo de CPU evitando eso, a menos que necesite el valor final para fines de visualización. Incluso puede AGRUPAR POR el valor no convertido y poner la conversión solo en la cláusula SELECT:
select Convert(datetime, DateDiff(dd, 0, Tm))
from (select '2010-09-12 00:00:00.003') X (Tm)
group by DateDiff(dd, 0, Tm)
Además, ¿ve cómo las conversiones numéricas solo toman un poco más de tiempo para volver a convertirse datetime
, pero la varchar
conversión casi se duplica? Esto revela la parte de la CPU que se dedica al cálculo de la fecha en las consultas. Hay partes del uso de la CPU que no involucran el cálculo de la fecha, y esto parece ser algo cercano a 19875 ms en las consultas anteriores. Luego, la conversión requiere una cantidad adicional, por lo que si hay dos conversiones, esa cantidad se usa aproximadamente el doble.
Un examen más detenido revela que, en comparación con Convert(, 112)
, la Convert(, 101)
consulta tiene un gasto adicional de CPU (¿ya que usa una varchar
conversión más larga ?), Porque la segunda conversión a date
no cuesta tanto como la conversión inicial a varchar
, pero con Convert(, 112)
ella está más cerca del mismo 20000 ms costo base de la CPU.
Aquí están esos cálculos sobre el tiempo de CPU que utilicé para el análisis anterior:
method round single base
date 21324 19891 18458
int 23031 21453 19875
datediff 23782 23218 22654
float 36891 29312 21733
varchar-112 102984 64016 25048
varchar-101 123375 65609 7843
round es el tiempo de CPU para un viaje de ida y vuelta a datetime
.
single es el tiempo de CPU para una conversión única al tipo de datos alternativo (el que tiene el efecto secundario de eliminar la porción de tiempo).
la base es el cálculo de restar de single
la diferencia entre las dos invocaciones: single - (round - single)
. Es una cifra datetime
aproximada que asume la conversión hacia y desde ese tipo de datos y es aproximadamente la misma en cualquier dirección. Parece que esta suposición no es perfecta, pero está cerca porque todos los valores están cerca de 20000 ms con una sola excepción.
Una cosa más interesante es que el costo base es casi igual al Convert(date)
método único (que tiene que ser un costo casi 0, ya que el servidor puede extraer internamente la porción del día entero directamente de los primeros cuatro bytes del datetime
tipo de datos).
Conclusión
Entonces, lo que parece es que el varchar
método de conversión de una sola dirección toma alrededor de 1.8 μs y el DateDiff
método de una sola dirección toma alrededor de 0.18 μs. Estoy basando esto en el tiempo de "CPU base" más conservador en mi prueba de 18458 ms en total para 25,920,000 filas, entonces 23218 ms / 25920000 = 0.18 μs. La aparente mejora de 10x parece mucho, pero francamente es bastante pequeña hasta que se trata de cientos de miles de filas (617k filas = 1 segundo de ahorro).
Incluso con esta pequeña mejora absoluta, en mi opinión, el DateAdd
método gana porque es la mejor combinación de rendimiento y claridad. La respuesta que requiere un "número mágico" 0.50000004
va a morder a alguien algún día (cinco ceros o seis ???), además es más difícil de entender.
Notas adicionales
Cuando consigo un poco de tiempo Voy a cambio 0.50000004
de '12:00:00.003'
y ver cómo lo hace. Se convierte al mismo datetime
valor y me resulta mucho más fácil de recordar.
Para aquellos interesados, las pruebas anteriores se ejecutaron en un servidor donde @@ Version devuelve lo siguiente:
Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) 9 de julio de 2008 14:43:34 Copyright (c) 1988-2008 Microsoft Corporation Standard Edition en Windows NT 5.2 (compilación 3790: Service Pack 2)
char
lugar devarchar
?select round(sysdate) from dual
y definitivamente lo necesitamos en Sql Server.date
tipo de datos es más rápida, como se muestra en mis pruebas anteriores.SQL Server 2008 tiene un nuevo tipo de datos de fecha y esto simplifica este problema a:
SELECT CAST(CAST(GETDATE() AS date) AS datetime)
fuente
DATEADD(DATEDIFF())
método para reducir la parte de tiempo arroja una excepción. Cuandodatetime2
select cast(CAST(convert(datetime2(0), '0218-09-12', 120) AS date) as datetime2)
Itzik Ben-Gan en DATETIME Calculations, Part 1 (SQL Server Magazine, febrero de 2007) muestra tres métodos para realizar dicha conversión (de más lento a más rápido ; la diferencia entre el segundo y el tercer método es pequeña):
SELECT CAST(CONVERT(char(8), GETDATE(), 112) AS datetime) SELECT DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) SELECT CAST(CAST(GETDATE() - 0.50000004 AS int) AS datetime)
Un lector sugiere su técnica (lanzar para flotar ) en la edición de abril de la revista. Según él, tiene un rendimiento comparable al de la segunda técnica presentada anteriormente.
fuente
SELECT CAST(CAST(GETDATE() - '12:00:00.003' AS int) AS datetime)
hacerlo, ya que significa algo para mí y es mucho más fácil de recordar.Convert(date, GetDate())
.Su
CAST
-FLOOR
-CAST
ya parece ser la forma óptima, al menos en MS SQL Server 2005.Algunas otras soluciones que he visto tienen una conversión de cadenas, como
Select Convert(varchar(11), getdate(),101)
en ellas, que es más lenta en un factor de 10.fuente
Por favor, inténtalo:
SELECT CONVERT(VARCHAR(10),[YOUR COLUMN NAME],105) [YOURTABLENAME]
fuente
SQL2005: recomiendo emitir en lugar de dateadd. Por ejemplo,
select cast(DATEDIFF(DAY, 0, datetimefield) as datetime)
promediado alrededor de un 10% más rápido en mi conjunto de datos, que
select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0)
(y la conversión a smalldatetime fue aún más rápida)
fuente