내가 사용하는 것은 다음과 같습니다.
SELECT CAST(FLOOR(CAST(getdate() as FLOAT)) as DATETIME)
더 좋고 우아한 방법이있을 수 있다고 생각합니다.
요구 사항 :
- 가능한 한 빨라야합니다 (주조 횟수가 적을수록 좋습니다).
- 최종 결과는
datetime
문자열이 아닌 유형 이어야 합니다.
답변:
SQL Server 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 천 6 백만 행에서 엄청난 비용이 발생하고 메서드 간의 성능 차이를 숨길 수 있으므로 행을 클라이언트로 다시 반환하지 않는 것이 목적입니다.
성능 결과
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 또는 비교 만 수행하는 경우 .NET Framework로 다시 변환 할 필요가 없습니다 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)
그것이 가까이 같은 20000 ms 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
round 는로 돌아가는 왕복의 CPU 시간입니다 datetime
.
single 은 대체 데이터 유형 (시간 부분을 제거하는 부작용이있는 유형)으로의 단일 변환에 대한 CPU 시간입니다.
base 는 single
두 호출 간의 차이 에서 뺀 계산입니다 single - (round - single)
. 해당 데이터 유형과의 변환을 가정하고 datetime
어느 방향 으로든 거의 동일한 야구장 수치입니다 . 이 가정은 완벽하지는 않지만 값이 한 가지 예외를 제외하고 모두 20000ms에 가깝기 때문에 가깝습니다.
한 가지 더 흥미로운 점은 기본 비용이 단일 Convert(date)
방법 과 거의 동일하다는 것입니다 (서버가 datetime
데이터 유형 의 처음 4 바이트에서 정수 일 부분을 내부적으로 추출 할 수 있으므로 비용이 거의 0이어야 함 ).
결론
따라서 단일 방향 varchar
변환 방법은 약 1.8 μs가 걸리고 단일 방향 DateDiff
방법은 약 0.18 μs가 걸립니다. 필자는 25,920,000 행에 대해 총 18458ms를 테스트 할 때 가장 보수적 인 "기본 CPU"시간을 기준으로하므로 23218ms / 25920000 = 0.18μs입니다. 명백한 10 배 개선은 많은 것처럼 보이지만 수십만 개의 행 (617k 행 = 1 초 절약)을 처리하기 전까지는 솔직히 매우 작습니다.
이 작은 절대적인 개선을 감안할 때, 제 생각 DateAdd
에는 성능과 명확성의 최상의 조합이기 때문에이 방법이 승리합니다. "매직 넘버"를 요구하는 대답은 0.50000004
언젠가 누군가를 물릴 것입니다 (5 개의 0 또는 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 Microsoft Corporation Standard Edition on Windows NT 5.2 (빌드 3790 : 서비스 팩 2)
char
대신 사용하면 시간차 가 varchar
있습니까?
select round(sysdate) from dual
Sql Server에 확실히 필요합니다.
date
위의 테스트에서 볼 수 있듯이 데이터 형식으로 변환하는 것이 가장 빠릅니다.
SQL Server 2008에는 새로운 날짜 데이터 형식이 있으며 이로 인해이 문제가 다음과 같이 단순화됩니다.
SELECT CAST(CAST(GETDATE() AS date) AS datetime)
DATEADD(DATEDIFF())
시간 부분을 줄이는 방법이 예외를 던졌습니다. 내가 캐스팅 할 때 결과 다시 datetime2
당신의 방법은 잘 작동select cast(CAST(convert(datetime2(0), '0218-09-12', 120) AS date) as datetime2)
DATETIME Calculations, Part 1 (SQL Server Magazine, 2007 년 2 월)의 Itzik Ben-Gan은 이러한 변환을 수행하는 세 가지 방법을 보여줍니다 ( 가장 느림에서 가장 빠름 , 두 번째와 세 번째 방법의 차이는 작음).
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 월호에 독자가 여러분의 기술 ( 부동으로 캐스팅 )을 제안했습니다. 그에 따르면 위에서 제시 한 두 번째 기술과 비슷한 성능을 가지고 있습니다.
SELECT CAST(CAST(GETDATE() - '12:00:00.003' AS int) AS datetime)
에게 의미가 있고 기억하기가 훨씬 쉽기 때문에 대신 선호 합니다.
Convert(date, GetDate())
..
귀하는 CAST
- FLOOR
- CAST
이미 적어도 MS SQL 서버 2005, 최적의 방법이 될 것으로 보인다.
내가 본 다른 솔루션 Select Convert(varchar(11), getdate(),101)
에는 10 배 느리게 문자열 변환 이 있습니다.
SQL2005 : dateadd 대신 캐스트를 권장합니다. 예를 들면
select cast(DATEDIFF(DAY, 0, datetimefield) as datetime)
내 데이터 세트에서 평균 약 10 % 더 빠릅니다 .
select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0)
(그리고 smalldatetime으로 캐스팅하는 것이 여전히 더 빠릅니다)