Efter at have fulgt op på mit tidligere indlæg om trimning af tid fra datetime, blev jeg tilskyndet til at demonstrere mere tydeligt ydeevneegenskaberne for forskellige metoder uden at involvere dataadgang. I det oprindelige indlæg sammenlignede jeg hurtigt syv forskellige metoder til uafhængigt at konvertere en datetime-værdi til en dato, viste, at forskellene var ubetydelige, og gik derefter direkte over til at analysere brugen af disse metoder i faktiske forespørgsler, der returnerer data.
I dette indlæg ønskede jeg at vise flere forskellige måder at trimme tiden fra dato og klokkeslæt (18 forskellige måder faktisk!), uden at introducere nogen egentlige data, for at se, om vi kunne proklamere en "hurtigste" måde at udføre denne opgave på.
Metoderne
Her er de 18 metoder, jeg ville teste, nogle taget fra blogindlægget Madhivanan påpegede efter mit tidligere indlæg:
DECLARE @d DATETIME, @ds DATETIME = SYSDATETIME();
Testen
Jeg lavede en løkke, hvor jeg ville køre hver konvertering 1.000.000 gange, og derefter gentage processen for alle 18 konverteringsmetoder 10 gange. Dette ville give metrics for 10.000.000 konverteringer for hver metode, hvilket eliminerer enhver signifikant statistisk skævhed.
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;
Resultaterne
Jeg kørte dette på en Windows 8 VM med 8 GB RAM og 4 vCPU'er, der kører SQL Server 2012 (11.0.2376). Her er resultater i tabelform, sorteret efter gennemsnitlig varighed, hurtigst først:
Og her er en grafisk fremstilling af den gennemsnitlige varighed: