Dando sequência ao meu post anterior sobre o corte de tempo de datetime, fui estimulado a demonstrar mais claramente as características de desempenho de vários métodos sem envolver o acesso a dados. No post original, comparei rapidamente sete métodos diferentes de converter um valor de data e hora em uma data de forma independente, mostrei que as diferenças eram insignificantes e, em seguida, passei direto para a análise do uso desses métodos em consultas reais que retornam dados.
Neste post, eu queria mostrar várias maneiras diferentes de cortar o tempo de datetime (18 maneiras diferentes na verdade!), sem introduzir nenhum dado real, para ver se poderíamos proclamar uma maneira "mais rápida" de executar essa tarefa.
Os métodos
Aqui estão os 18 métodos que eu testaria, alguns retirados do post do blog que Madhivanan apontou após o meu post anterior:
DECLARE @d DATETIME, @ds DATETIME = SYSDATETIME();
O Teste
Criei um loop em que executaria cada conversão 1.000.000 vezes e, em seguida, repetiria o processo para todos os 18 métodos de conversão 10 vezes. Isso forneceria métricas para 10.000.000 de conversões para cada método, eliminando qualquer distorção estatística significativa.
CREATE TABLE #s(j INT, ms INT); GO SET NOCOUNT ON; GO DECLARE @j INT = 1, @x INT, @i INT = 1000000; DECLARE @t DATETIME2, @d DATETIME, @ds DATETIME = SYSDATETIME(); WHILE @j <= 18 BEGIN SELECT @x = 1, @t = SYSDATETIME(); WHILE @x <= @i BEGIN IF @j = 1 SET @d = DATEDIFF(DAY, 0, @ds); IF @j = 2 SET @d = CAST(@ds AS INT); IF @j = 3 SET @d = CAST(CONVERT(CHAR(8), @ds, 112) AS DATETIME); IF @j = 4 SET @d = DATEADD(DAY, DATEDIFF(DAY, 0, @ds), 0); IF @j = 5 SET @d = CAST(CAST(SUBSTRING(CAST(@ds AS BINARY(8)), 1, 4) AS BINARY(8)) AS DATETIME); IF @j = 6 SET @d = CONVERT(CHAR(8), @ds, 112); IF @J = 7 SET @d = CAST(CAST(@ds AS VARCHAR(11)) AS DATETIME); IF @J = 8 SET @d = @ds - CONVERT(CHAR(10), @ds, 108); IF @J = 9 SET @d = @ds - CAST(CAST(@ds AS TIME) AS DATETIME); IF @J = 10 SET @d = CAST(FLOOR(CAST(@ds AS FLOAT)) AS DATETIME); IF @J = 11 SET @d = CAST(CAST(CAST(CAST(@ds AS BINARY(8)) AS BINARY(4)) AS BINARY(8)) AS DATETIME); IF @J = 12 SET @d = @ds - CAST(@ds AS BINARY(4)); IF @J = 13 SET @d = DATEADD(DAY, CONVERT(INT, @ds - 0.5), 0); IF @J = 14 SET @d = CONVERT(DATETIME, FORMAT(@ds, N'yyyy-MM-dd')); IF @J = 15 SET @d = CONVERT(DATETIME,CONVERT(INT,CONVERT(FLOAT,@ds))); IF @J = 16 SET @d = CAST(CAST(CAST(CAST(@ds AS BINARY(8)) AS BIGINT) & 0XFFFFFFFF00000000 AS BINARY(8)) AS DATETIME); IF @J = 17 SET @d = CONVERT(DATE, @ds); IF @j = 18 SET @d = CAST(@ds AS DATE); SET @x += 1; END INSERT #s SELECT @j, DATEDIFF(MILLISECOND, @t, SYSDATETIME()); SET @j += 1; END GO 10 SELECT j, method = CASE ... END, MIN(ms), MAX(ms), AVG(ms) FROM #s GROUP BY j ORDER BY j;
Os resultados
Eu executei isso em uma VM Windows 8, com 8 GB de RAM e 4 vCPUs, executando o SQL Server 2012 (11.0.2376). Aqui estão os resultados tabulares, classificados por duração média, mais rápidos primeiro:
E aqui está uma representação gráfica da duração média: