문제

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 그리고 아마도 다른 쓰레기, 또는 아마도 더 높은 정밀 시간 단위를 사용하고 나누기).

이 원칙은 시간, 일 또는 달과 같은 더 큰 단위를 계산할 때 특히 중요합니다. ㅏ DateDiff1 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.

대안으로 사용할 수 있습니다 계산 된 열.

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