문제

내가 사용하는 것은 다음과 같습니다.

SELECT CAST(FLOOR(CAST(getdate() as FLOAT)) as DATETIME)

더 좋고 우아한 방법이 있을 수 있다고 생각합니다.

요구사항:

  • 가능한 한 빨라야 합니다(캐스팅이 적을수록 좋습니다).
  • 최종 결과는 다음과 같아야 합니다. datetime 문자열이 아닌 유형을 입력하세요.
도움이 되었습니까?

해결책

SQL 서버 2008 이상

물론 SQL Server 2008 이상에서 가장 빠른 방법은 Convert(date, @date).이는 다시 캐스팅될 수 있습니다. datetime 또는 datetime2 필요하다면.

SQL Server 2005 및 이전 버전에서 실제로 가장 좋은 것은 무엇입니까?

SQL Server의 날짜에서 시간을 자르는 가장 빠른 방법에 대한 일관되지 않은 주장을 본 적이 있으며 일부 사람들은 테스트를 했다고 말하기도 했지만 내 경험은 달랐습니다.따라서 좀 더 엄격한 테스트를 수행하고 모든 사람이 스크립트를 갖게 하여 내가 실수를 하면 사람들이 나를 수정할 수 있도록 합시다.

부동 소수점 변환이 정확하지 않습니다

첫째, 전환을 멀리하겠습니다. datetime 에게 float, 올바르게 변환되지 않기 때문입니다.시간 제거 작업을 정확하게 수행하면 무사할 수도 있지만, 이것이 안전한 작업이고 개발자에게 암묵적으로 전달되기 때문에 사용하는 것은 좋지 않은 생각이라고 생각합니다. 그렇지 않다.구경하다:

declare @d datetime;
set @d = '2010-09-12 00:00:00.003';
select Convert(datetime, Convert(float, @d));
-- result: 2010-09-12 00:00:00.000 -- oops

이것은 우리의 코드나 온라인 예제를 통해 사람들에게 가르쳐야 할 내용이 아닙니다.

또한 가장 빠른 방법도 아닙니다!

증명 – 성능 테스트

다양한 방법이 실제로 어떻게 작동하는지 확인하기 위해 직접 몇 가지 테스트를 수행하려는 경우 테스트를 더 자세히 실행하려면 다음 설정 스크립트가 필요합니다.

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;  -- 25,920,000 rows

이렇게 하면 데이터베이스에 427.57MB의 테이블이 생성되며 실행하는 데 15~30분 정도 소요됩니다.데이터베이스가 작고 10% 증가로 설정된 경우 먼저 크기를 충분히 크게 설정한 경우보다 시간이 더 오래 걸립니다.

이제 실제 성능 테스트 스크립트를 살펴보겠습니다.행을 클라이언트에 다시 반환하지 않는 것이 목적입니다. 이는 2,600만 개의 행에 엄청난 비용이 들고 메서드 간의 성능 차이를 숨길 수 있기 때문입니다.

성과 결과

set statistics time on;
-- (All queries are the same on io: logical reads 54712)
GO
declare
    @dd date,
    @d datetime,
    @di int,
    @df float,
    @dv varchar(10);

-- Round trip back to datetime
select @d = CONVERT(date, Tm) from AllDay; -- CPU time = 21234 ms,  elapsed time = 22301 ms.
select @d = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 23031 ms, elapsed = 24091 ms.
select @d = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23782 ms, elapsed = 24818 ms.
select @d = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 36891 ms, elapsed = 38414 ms.
select @d = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 102984 ms, elapsed = 109897 ms.
select @d = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 103390 ms,  elapsed = 108236 ms.
select @d = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 123375 ms, elapsed = 135179 ms.

-- Only to another type but not back
select @dd = Tm from AllDay; -- CPU time = 19891 ms,  elapsed time = 20937 ms.
select @di = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 21453 ms, elapsed = 23079 ms.
select @di = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23218 ms, elapsed = 24700 ms
select @df = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 29312 ms, elapsed = 31101 ms.
select @dv = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 64016 ms, elapsed = 67815 ms.
select @dv = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 64297 ms,  elapsed = 67987 ms.
select @dv = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 65609 ms, elapsed = 68173 ms.
GO
set statistics time off;

일부 혼란스러운 분석

이에 대한 몇 가지 참고 사항.우선, GROUP BY나 비교만 수행하는 경우 다시 변환할 필요가 없습니다. datetime.따라서 표시 목적으로 최종 값이 필요하지 않은 한 이를 피함으로써 일부 CPU를 절약할 수 있습니다.변환되지 않은 값을 GROUP BY로 처리하고 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)

또한 숫자 변환이 다시 변환하는 데 시간이 약간 더 걸리는지 확인하세요. datetime, 하지만 varchar 전환율이 거의 두 배가 되나요?이는 쿼리에서 날짜 계산에 사용되는 CPU 부분을 나타냅니다.CPU 사용량 중 날짜 계산과 관련되지 않은 부분이 있으며 이는 위 쿼리에서 19875ms에 가까운 것으로 보입니다.그런 다음 전환에는 약간의 추가 금액이 필요하므로 두 번의 전환이 있는 경우 해당 금액은 약 두 배로 사용됩니다.

더 많은 조사 결과에 비해 Convert(, 112), Convert(, 101) 쿼리에는 추가 CPU 비용이 발생합니다(더 긴 시간을 사용하기 때문에). varchar?), 두 번째 변환이 다시 date 초기 전환 비용만큼 비용이 들지 않습니다. varchar, 하지만 함께 Convert(, 112) 동일한 20000ms CPU 기본 비용에 더 가깝습니다.

위 분석에 사용한 CPU 시간 계산은 다음과 같습니다.

     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
  • 둥근 다시 왕복하는 데 소요되는 CPU 시간입니다. datetime.

  • 하나의 대체 데이터 유형(시간 부분을 제거하는 부작용이 있는 유형)으로의 단일 변환에 대한 CPU 시간입니다.

  • 베이스 에서 빼는 계산입니다. single 두 호출의 차이점은 다음과 같습니다. single - (round - single).해당 데이터 유형과의 변환을 가정하는 야구장 수치입니다. datetime 어느 방향에서나 거의 동일합니다.이 가정은 완벽하지는 않지만 한 가지 예외를 제외하고 값이 모두 20000ms에 가깝기 때문에 유사합니다.

또 하나 흥미로운 점은 기본 비용이 단일 비용과 거의 동일하다는 것입니다. Convert(date) 방법(서버가 내부적으로 처음 4바이트에서 바로 정수 일 부분을 추출할 수 있으므로 비용은 거의 0이어야 함) datetime 데이터 형식).

결론

그래서 보이는 것은 단일 방향입니다. varchar 변환 방법은 약 1.8μs가 소요되며 단방향 DateDiff 방법에는 약 0.18μs가 소요됩니다.이는 25,920,000개 행에 대해 총 18458ms의 테스트에서 가장 보수적인 '기본 CPU' 시간을 기반으로 하므로 23218ms / 25920000 = 0.18μs입니다.명백한 10배 개선은 많은 것처럼 보이지만 수십만 개의 행(617,000개 행 = 1초 절약)을 처리하기 전까지는 솔직히 매우 작습니다.

이 작은 절대적인 개선에도 불구하고 제 생각에는 DateAdd 방법은 성능과 명확성의 최상의 조합이기 때문에 승리합니다."마법의 숫자"가 필요한 대답 0.50000004 언젠가 누군가를 물게 될 것입니다 (0이 5개 또는 6???). 게다가 이해하기가 더 어렵습니다.

추가 참고 사항

시간나면 바꿔야지 0.50000004 에게 '12:00:00.003' 어떻게 되는지 확인해 보세요.동일하게 변환됩니다. datetime 가치가 있고 기억하기가 훨씬 쉽다고 생각합니다.

관심 있는 분들을 위해 위 테스트는 @@Version이 다음을 반환하는 서버에서 실행되었습니다.

Microsoft SQL Server 2008(RTM) - 10.0.1600.22(Intel X86) 2008년 7월 9일 14:43:34 Copyright (c) 1988-2008 Windows NT 5.2의 Microsoft Corporation Standard Edition(빌드 3790:서비스 팩 2)

다른 팁

SQL Server 2008에는 새로운 기능이 있습니다. 날짜 데이터 형식 이는 이 문제를 다음과 같이 단순화합니다.

SELECT CAST(CAST(GETDATE() AS date) AS datetime)

이직 벤간 DATETIME 계산, 1부 (SQL Server Magazine, 2007년 2월)에서는 이러한 변환을 수행하는 세 가지 방법을 보여줍니다.가장 느린 것에서 가장 빠른 것;두 번째 방법과 세 번째 방법의 차이는 작습니다.)

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)

귀하의 기술(캐스팅 뜨다)은 잡지 4월호에 한 독자가 제안한 내용입니다.그에 따르면, 위에서 제시한 두 번째 기술과 비슷한 성능을 가지고 있다고 합니다.

당신의 CAST-FLOOR-CAST 적어도 MS SQL Server 2005에서는 이미 최적의 방법인 것 같습니다.

내가 본 다른 솔루션에는 다음과 같은 문자열 변환이 있습니다. Select Convert(varchar(11), getdate(),101) 그 속도는 10배 정도 느립니다.

시도해 보십시오:

SELECT CONVERT(VARCHAR(10),[YOUR COLUMN NAME],105) [YOURTABLENAME]

SQL2005:dateadd 대신 캐스트를 권장합니다.예를 들어,

select cast(DATEDIFF(DAY, 0, datetimefield) as datetime)

평균 10% 정도 더 빠르게 내 데이터세트에서는

select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0)

(그리고 smalldatetime으로 캐스팅하는 것이 더 빨랐습니다)

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top