Database
 sql >> Base de Dados >  >> RDS >> Database

Aparando o tempo de datetime – um acompanhamento


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: