문제
SQL 문에서 Datediff를 사용하고 있습니다. 나는 그것을 선택하고 있으며, 여기서 조항에서도 그것을 사용해야합니다. 이 진술은 작동하지 않습니다 ...
SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE InitialSave <= 10
메시지가 제공됩니다. 잘못된 열 이름 "이니셜"
그러나이 진술은 잘 작동합니다 ...
SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE DATEDIFF(ss, BegTime, EndTime) <= 10
저의 프로그래머는 이것이 비효율적이라고 말합니다 (내가 함수를 두 번 호출하는 것처럼 보입니다).
그래서 두 가지 질문입니다. 첫 번째 진술이 작동하지 않는 이유는 무엇입니까? 두 번째 진술을 사용하여 수행하는 것이 효과적이지 않습니까?
해결책
Where 명령문의 select 문에 정의 된 열에 액세스 할 수 없습니다. WHERE가 실행 된 후까지 생성되지 않기 때문입니다.
그러나 당신은 이것을 할 수 있습니다
select InitialSave from
(SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable) aTable
WHERE InitialSave <= 10
사이드 니트로서 - 이것은 본질적으로 Datediff를 처음 정의 된 위치에 따라 WHER 문으로 옮깁니다. 문서에서 열에 함수를 사용하여 진술은 인덱스가 효율적으로 사용되지 않으며 가능한 경우 피해야하지만 Datediff를 사용해야하는 경우 수행해야합니다!
다른 팁
메모: 원래이 대답을 썼을 때 열 중 하나의 색인이 다른 답변보다 더 잘 수행되는 쿼리를 만들 수 있다고 말했습니다 (그리고 Dan Fuller의 언급). 그러나 나는 100% 올바르게 생각하지 않았다. 사실, 계산 된 열 또는 인덱스 (구체화 된)보기가 없으면 전체 테이블 스캔이 될 것입니다. 필수의, 비교되는 두 날짜 열은 같은 테이블!
아래 정보에는 여전히 가치가 있다고 생각합니다. 즉, 1) 올바른 상황에서 성능 향상 가능성, 다른 테이블의 열 사이에 비교 될 때와 2) 모범 사례 및 재구성을 따르는 SQL 개발자의 습관 홍보 올바른 방향으로 그들의 생각.
조건을 엄청나게 만듭니다
내가 언급하는 모범 사례는 비교 연산자의 한쪽에 단독으로 한 열을 움직이는 것 중 하나입니다.
SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM dbo.MyTable T
WHERE T.EndTime <= T.BegTime + '00:00:10'
내가 말했듯이, 이것은 단일 테이블의 스캔을 피하지 않을 것이지만, 이와 같은 상황에서는 큰 차이를 만들 수 있습니다.
SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM
dbo.BeginTime B
INNER JOIN dbo.EndTime E
ON B.BeginTime <= E.EndTime
AND B.BeginTime + '00:00:10' > E.EndTime
EndTime
비교의 한쪽에있는 두 조건 모두에 있습니다. 그것을 가정합니다 BeginTime
테이블은 줄이 적고 있습니다 EndTime
테이블에는 열에 색인이 있습니다 EndTime
, 이것은 사용하는 것보다 훨씬 더 잘 수행됩니다. DateDiff(second, B.BeginTime, E.EndTime)
. 지금이야 사기 가능, 이는 유효한 "검색 인수"가 있음을 의미합니다. 스캔 그만큼 BeginTime
테이블, 가능합니다 찾다. 목표물 탐색 로 EndTime
테이블. 연산자의 한쪽에있는 열 자체가 필요한 신중한 선택이 필요합니다. BeginTime
전환하기 위해 대수학을 수행함으로써 그 자체로 AND B.BeginTime > E.EndTime - '00:00:10'
Datediff의 정밀도
나는 또한 그것을 지적해야한다 DateDiff
돌아 오지 않습니다 경과 시간이지만 대신 수를 계산합니다 경계 교차. 전화 한 경우 DateDiff
초를 사용하여 반환됩니다 1
, 이것은 의미 할 수 있습니다 3 ms
경과 시간이거나 의미가있을 수 있습니다 1997 ms
! 이것은 본질적으로 +-1 타임 단위의 정밀도입니다. +-1/2 시간 단위의 더 나은 정밀도를 위해 다음 쿼리를 비교할 수 있습니다. 0
에게 EndTime - BegTime
:
SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
FROM MyTable
WHERE EndTime <= BegTime + '00:00:10'
이는 이제 최대 1 초의 최대 반올림 오류가 있으며 (실제로는 바닥 () 작업)이 아닙니다. 당신은 만 빼낼 수 있습니다 datetime
데이터 유형-빼기 a date
또는 a time
당신이 변환해야 할 가치 datetime
또는 다른 방법을 사용하여 더 나은 정밀도를 얻습니다 (많은 DateAdd
, DateDiff
그리고 아마도 다른 쓰레기, 또는 아마도 더 높은 정밀 시간 단위를 사용하고 나누기).
이 원칙은 시간, 일 또는 달과 같은 더 큰 단위를 계산할 때 특히 중요합니다. ㅏ DateDiff
의 1 month
62 일 간격이 될 수 있습니다 (2013 년 7 월 1 일 -2013 년 8 월 31 일 생각)!
"작업"으로 만들어주는 것 외에도 색인을 사용해야합니다.
인덱스가있는 계산 된 열 또는 색인이있는 뷰를 사용하면 스캔을 테이블 스캔합니다. 당신이 충분한 줄을 얻으면 당신은 통증 느린 스캔의!
계산 된 열 및 색인 :
ALTER TABLE MyTable ADD
ComputedDate AS DATEDIFF(ss,BegTime, EndTime)
GO
CREATE NONCLUSTERED INDEX IX_MyTable_ComputedDate ON MyTable
(
ComputedDate
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
보기 및 색인 생성 :
CREATE VIEW YourNewView
AS
SELECT
KeyValues
,DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
GO
CREATE CLUSTERED INDEX IX_YourNewView
ON YourNewView(InitialSave)
GO
열 별칭 대신 함수를 사용해야합니다. count (*) 등과 동일합니다. Pita.
대안으로 사용할 수 있습니다 계산 된 열.