SELECT 및 GROUP BY 절의 SQL 계산 필드


11

종종 MS SQL Server 데이터베이스를 쿼리 할 때 다음과 같은 계산 된 필드를 만들어야합니다.

(CASE WHEN A.type = 'Workover' THEN 'Workover' 
      ELSE (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' 
                 WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' 
                 WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' 
                 ELSE 'Other' 
            END)
END)

그런 다음이 계산 된 필드별로 결과를 그룹화해야합니다. 따라서 SELECT 및 GROUP BY 절에서 동일한 계산을 수행합니다. SQL Server가 실제로 이러한 계산을 두 번 수행합니까, 아니면 한 번만 수행해도 충분합니까?

답변:


13

SELECT 및 GROUP BY 절 모두에서 동일한 계산이 있습니다. SQL Server가 실제로 이러한 계산을 두 번 수행합니까, 아니면 한 번만 수행해도 충분합니까?

간단한 대답은 SQL Server가 실행 시간에 스칼라식이 언제 언제 평가되는지에 대한 일반적인 보증을하지 않는다는 것입니다.

스칼라 표현식의 배치, 실행 및 캐싱과 관련하여 옵티 마이저 및 실행 엔진 내에는 모든 종류의 복잡하고 문서화되지 않은 동작이 있습니다. 온라인은 이것에 대해 말을 많이 가지고 있지만하지 않는 것이 말을하는 일은 이것이다 :

계산 스칼라 설명

이것은 내가 이전에 암시 한 행동 중 하나, 표현의 실행을 연기하는 것을 설명합니다. 나는 이 블로그 게시물에서 다른 현재 행동 (언제든지 변경할 수 있음) 대해 썼습니다 .

또 다른 고려 사항은 쿼리 최적화 프로그램 사용하는 비용 모델 이 현재 스칼라 표현식에 대한 비용 추정 방식을 많이 수행하지 않는다는 것입니다. 강력한 원가 체계가 없으면 현재 결과는 광범위한 휴리스틱 또는 순수한 기회를 기반으로합니다.

매우 간단한 표현식의 경우 대부분의 경우 표현식이 한 번 또는 여러 번 평가되는지 여부에 큰 차이가 없습니다. 즉, 표현식을 매우 많이 중복 평가할 때 성능에 부정적인 영향을 미치거나 실행의 병렬 분기에서 평가하는 것이 유리한 단일 스레드에서 평가가 수행되는 큰 쿼리가 발생했습니다. 계획.

요약하면 현재 동작은 정의되어 있지 않으며 실행 계획에 아무런 도움이되지 않습니다 (블로그 게시물 에서처럼 자세한 엔진 동작을 검사하기 위해 디버거를 연결하는 것이 항상 편리한 것은 아닙니다).

스칼라 평가 문제가 성능에 중요한 경우가 발생하면 Microsoft 지원 센터에서 문제를 제기하십시오. 향후 버전의 제품을 개선하기 위해 피드백을 제공하는 가장 좋은 방법입니다.


3

귀하의 질문에 대한 의견에서 알 수 있듯이 대답은 (적어도 적어도 "예")입니다. SQL Server는 일반적으로 재 계산을 피할 수있을 정도로 똑똑합니다. SQL Server Management Studio 내에서 실행 계획을 표시하여이를 확인할 수 있습니다. 계산 된 각 필드가 지정됩니다 Exprxxxxx(여기서 xxxxx는 숫자 임). 무엇을 찾아야하는지 알고 있다면 같은 표현을 사용하는지 확인할 수 있어야합니다.

토론에 추가하기 위해 다른 미적 옵션은 일반적인 테이블 표현식입니다 .

with [cte] as
(
    select
        (case when a.type = 'workover' then 'workover' else 
        (case when substring(c.category, 2, 1) = 'd' then 'drilling'
              when substring(c.category, 2, 1) = 'c' then 'completion'
              when substring(c.category, 2, 1) = 'w' then 'workover'
              else 'other' end)
         end)) as [group_key],
         *
    from
        [some_table]
)
select
    [group_key],
    count(*) as [count]
from
    [cte]
group by
    [group_key]

짧은 대답은 기능적으로 뷰와 동일하지만 다음 명령문에서만 사용할 수 있습니다. 중첩 테이블을 피하기 때문에 파생 테이블에 대한 대체로 읽기 쉬운 대안이라고 생각합니다.

이 질문과 관련이 없지만 스스로 참조 할 수 있으며 재귀 쿼리를 구성하는 데 사용할 수 있습니다.


@Quick Joe Smith : Exprxxxxx에 대해서도 옳다고 생각합니다. 그러나 표현식에 OpType으로 수동으로 이름 (대소 문자 ... 끝)을 지정한 경우 GROUP BY 절에서 OpType 필드를 사용하면 열 이름이 잘못되었다는 오류가 발생합니다.
Dr. Drew

불행하게도, 종종 표현식을 두 번 지정하는 유일한 방법은 CTE, 뷰 또는 중첩 쿼리 중 하나를 사용하는 것입니다.
빠른 조 스미스

2
CROSS APPLY 에 대해 알지 않는 한 .
Andriy M

사용 cross apply이 경우에하는 것은 약간의 신축성이며, 불필요한 도입하여 가능성이 높다 해 성능 자체 조인 것입니다.
빠른 조 스미스

2
나는 당신이 그 제안을 "잡았다"고 생각하지 않습니다. 는 CROSS APPLY단지 같은 행의 열에서 별칭을 정의합니다. 가입 할 필요가 없습니다. 예SELECT COUNT(*), hilo FROM master..spt_values CROSS APPLY (VALUES(high + low)) V(hilo) GROUP BY hilo
Martin Smith

1

성능은 한 측면 일뿐입니다. 다른 하나는 유지 보수성입니다.

개인적으로 나는 다음과 같은 경향이있다.

SELECT T.GroupingKey, SUM(T.value)
FROM
(
    SELECT 
        A.*
        (CASE WHEN A.type = 'Workover' THEN 'Workover' ELSE 
        (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' ELSE 'Other' END)
        END) AS GroupingKey
    FROM Table AS A
) AS T

GROUP BY T.GroupingKey

최신 정보:

중첩을 원하지 않는 경우 복잡한 표현식을 사용해야하는 각 테이블에 대해 VIEW를 작성할 수 있습니다.

CREATE VIEW TableExtended
AS 
SELECT 
    A.*
    (CASE WHEN A.type = 'Workover' THEN 'Workover' ELSE 
    (CASE WHEN substring(C.category, 2, 1) = 'D' THEN 'Drilling' WHEN substring(C.category, 2, 1) = 'C' THEN 'Completion' WHEN substring(C.category, 2, 1) = 'W' THEN 'Workover' ELSE 'Other' END)
    END) AS GroupingKey
FROM Table AS A

그런 다음 추가 중첩을 수행하지 않고도 선택할 수 있습니다.

SELECT GroupingKey, SUM(value)
FROM TableExtended
GROUP BY GroupingKey
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.