대부분의 절에서 열 별칭을 사용할 수없는 방식으로 쿼리를 구문 분석하는 이유는 무엇입니까?


16

쿼리를 작성하는 동안 쿼리를 실행할 때 SELECT를 구문 분석하기 전에 SQL Server가 쿼리에서 WHERE를 구문 분석하는 것이 어렵다는 것을 알았습니다.

MSDN 문서 등은 일반적인 논리 파싱 순서 SELECT은 (따라서 "이런 개체 [별명]"의 오차가 다른 절에서 열 별칭을 사용하려고하지 않을 때의 결과) 거의 마지막 해석되도록 것을 말한다. 도 있었다 제안 별칭 (이 동작은 ANSI 표준의 일부임을 시사) ANSI 표준 준수 문제를 인용하여 Microsoft 팀에 의해 격추 된 사용 어디서나, 할 수 있도록하는가.

프로그래머 (DBA가 아님) 로서이 동작이 다소 혼란 스럽다는 것을 알았습니다. 왜냐하면 열 별칭을 갖는 목적을 크게 상실하거나 최소한 열 별칭이 훨씬 강력하다면 실제로 별칭을 사용할 수있는 유일한 위치 는 ORDER BY에 있기 때문에 쿼리 실행에서 앞서 구문 분석되었습니다 . 프로그래머로서 쿼리를 더욱 강력하고 편리하며 건조하게 만들 수있는 기회가없는 것 같습니다.

SELECT 및 ORDER BY 이외의 열에 별칭을 사용할 수 없다고 결정하는 다른 이유가 있기 때문에 눈에 띄는 문제가있는 것처럼 보입니다. 그러나 그 이유는 무엇입니까?

답변:


19

요약

없었던 논리적 인 이유 는 없지만, 이점은 적으며 즉시 명백하지 않을 수있는 함정이 있습니다.

연구 결과

나는 약간의 연구를하고 좋은 정보를 찾았다. 다음은 2012-08-09 17:49 GMT의 신뢰할 수있는 기본 소스 (익명으로 유지하려는)의 직접적인 인용입니다.

SQL이 처음 발명되었을 때 SELECT 절에 별칭이 없었습니다. 이것은 1986 년에 ANSI에 의해 언어가 표준화 될 때 수정 된 심각한 단점이었습니다.

이 언어는 "비 절차 적", 즉 언어를 찾는 방법을 지정하지 않고 원하는 데이터를 설명하기위한 것입니다. 따라서 내가 아는 한 SQL 구현이 쿼리를 처리하기 전에 전체 쿼리를 구문 분석 할 수없는 이유는 없으며 어디에서나 별칭을 정의하고 사용할 수 있습니다. 예를 들어 다음 쿼리가 유효하지 않은 이유는 없습니다.

select name, salary + bonus as pay
from employee
where pay > 100000

이것이 합리적인 쿼리라고 생각하지만 일부 SQL 기반 시스템은 구현 관련 이유로 별칭 사용에 대한 제한을 도입 할 수 있습니다. SQL Server가이 작업을 수행한다고 들었습니다.

SQL-86 표준에 대한 추가 연구와 최신 DBMS가 별칭 재사용을 지원하지 않는 이유에 관심이 있지만 아직까지는 아직 멀지 않았습니다. 우선, 문서를 어디서 구할 수 있는지 또는 누가위원회를 정확하게 구성했는지 알아낼 수 없습니다. 누구든지 도울 수 있습니까? 또한 SQL Server의 원래 Sybase 제품에 대해 더 알고 싶습니다.

이 연구와 몇 가지 추가 생각을 통해 다른 절에서 별칭을 사용하면 다른 언어 기능에 비해 DBMS 제조업체의 우선 순위가 결코 높지 않은 것으로 의심됩니다. 쿼리 작성자가 쉽게 해결할 수있는 것은 그리 큰 장애물이 아니기 때문에 다른 발전에 노력을 기울이는 것은 최적이 아닙니다. 또한 분명히 SQL 표준의 일부가 아니기 때문에 독점적 일 것입니다 (확실히 더 기다리고 있습니다). 그러나 약간 개선되어 DBMS 간의 SQL 호환성이 손상되었습니다. 비교하면 CROSS APPLY(실제로 외부 참조를 허용하는 파생 테이블에 지나지 않습니다.) 큰 변화이지만 독점은 다른 방식으로는 쉽게 수행 할 수없는 놀라운 표현력을 제공합니다.

어디서나 별칭을 사용할 때의 문제

SELECT 항목을 WHERE 절에 넣을 수 있으면 쿼리의 복잡성 (따라서 우수한 실행 계획을 찾는 복잡성)을 폭발적으로 확장 할 수있을뿐만 아니라 완전히 비논리적 인 것들을 생각 해낼 수 있습니다. 시험:

SELECT X + 5 Y FROM MyTable WHERE Y = X

MyTable에 이미 열 Y가있는 경우, 어느 것이 WHERE 절을 참조합니까? 해결책은 CTE 또는 파생 테이블을 사용하는 것입니다. 대부분의 경우 추가 비용이 들지 않지만 동일한 최종 결과를 얻을 수 있습니다. CTE와 파생 테이블은 별칭을 한 번만 사용할 수 있도록하여 모호성을 해결합니다.

또한 FROM 절에서 별명을 사용하지 않으면 의미가 있습니다. 당신은 이것을 할 수 없습니다 :

SELECT
   T3.ID + (SELECT Min(Interval) FROM Intervals WHERE IntName = 'T') CalcID
FROM
   Table1 T
   INNER JOIN Table2 T2
      ON T2.ID = CalcID
   INNER JOIN Table3 T3
      ON T2.ID = T3.ID

즉, (T2 비밀리 그 테이블은 가입리스트에 제시되기 전에, T3의 값을 참조하고있는 점에서), 원형의 기준 터무니 보이지. 이건 어때:

INSERT dbo.FinalTransaction
SELECT
   newid() FinalTransactionGUID,
   'GUID is: ' + Convert(varchar(50), FinalTransactionGUID) TextGUID,
   T.*
FROM
   dbo.MyTable T

newid () 함수가 실행 계획에 두 번 배치되어 두 열이 완전히 다른 값을 표시하게 만드는 데 얼마나 걸립니까? 위의 쿼리가 CTE 또는 파생 테이블에서 N 수준 깊이 사용되는 경우는 어떻습니까? 나는 당신이 상상할 수있는 것보다 문제가 더 나쁘다는 것을 보증한다. 쿼리 계획에서 상황이 한 번만 평가되는 시점이나 시점에 대해 불일치 문제 가 이미 발생했으며 Microsoft는 이를 해결하지 않을 것이라고 말했습니다.쿼리 대수를 올바르게 표현하기 때문에 일부는 예상치 못한 결과가 나오면 쿼리를 여러 부분으로 나눕니다. 체인 참조를 허용하고 잠재적으로 매우 긴 체인을 통해 순환 참조를 감지하는 것은 상당히 까다로운 문제입니다. 병렬 처리를 도입하면 제작에 악몽이 생깁니다.

참고 : WHERE 또는 GROUP BY에서 별칭을 사용해도 newid () 또는 rand ()와 같은 함수의 문제와 차이가 없습니다.

재사용 가능한 표현식을 작성하는 SQL Server 방법

CROSS APPLY / OUTER APPLY는 SQL Server에서 쿼리의 다른 곳에서 사용할 수있는 식을 만드는 한 가지 방법입니다 (FROM 절의 초반이 아님).

SELECT
   X.CalcID
FROM
   Table1 T
   INNER JOIN Table3 T3
      ON T.ID = T3.ID
   CROSS APPLY (
      SELECT
         T3.ID + (SELECT Min(Interval) FROM Intervals WHERE IntName = 'T') CalcID
   ) X
   INNER JOIN Table2 T2
      ON T2.ID = X.CalcID

이것은 두 가지 일을합니다.

  1. CROSS APPLY의 모든 표현식이 "네임 스페이스"(여기서는 X)를 가져오고 해당 네임 스페이스 내에서 고유하게합니다.
  2. CalcID가 X에서 나올뿐 아니라 X가 아직 소개되지 않았기 때문에 테이블 T1과 T3을 조인 할 때 X에서 어떤 것도 사용할 수없는 이유를 분명히 알 수 있습니다.

나는 실제로 CROSS APPLY를 좋아합니다. 그것은 나의 충실한 친구가되었고, 나는 그것을 항상 사용합니다. 부분 UNPIVOT (기본 구문을 사용하는 PIVOT / UNPIVOT 또는 UNPIVOT / PIVOT이 필요함)이 필요합니까? CROSS APPLY로 완료했습니다. 여러 번 재사용 할 계산 된 값이 필요하십니까? 끝난. 연결된 서버를 통한 통화에 대한 실행 순서를 엄격하게 시행해야합니까? 속도가 크게 향상되었습니다. 한 가지 유형의 행만 2 행으로 분할하거나 추가 조건이 필요합니까? 끝난.

따라서 DBMS SQL Server 2005 이상에서는 최소한 더 이상 불만을 제기 할 필요가 없습니다. CROSS APPLY는 원하는 방식으로 건조하는 방법입니다.


14

정확한 이유는 말할 수 없지만 CTE, 하위 쿼리, 파생 테이블 등을 사용하여 반복을 피하기 위해 식을 반복하는 해결 방법이 있음을 알려드립니다.

반복되는 표현식으로 쿼리를 표시하는 경우 표현식이 한 번만 나열되도록 다시 작성하는 방법을 보여줄 수 있습니다. 그러나 이것은 쿼리 작성 / 읽기의 복잡성을 감소 시키므로 효율성에 대해서는 크게 변하지 않을 것입니다. SQL Server는 일반적으로식이 반복된다는 것을 인식하는 데 능숙하며 해당 작업을 두 번 수행하지 않습니다. 다른 방법으로는 예외가 있지만 실제로 이러한 상황을 관찰 할 때 효율성에만 관심을 가져야합니다. 나는 당신이 쓴 대부분의 반복 표현이 실제로 계획에서 단 하나의 작업으로 축소 된 것으로 생각합니다.

모든 것이 말했듯이, 나는이 질문에서 내 대답의 일부를 반복 할 것입니다.

/dba/19762/why-is-the-select-clause-listed-first


다음은 표준에 따라 쿼리를 처리하는 방법에 대한 Joe Celko의 설명입니다 ( Celko 의 뉴스 그룹 게시물에서 인용 한 훔친 aspfaq.com article).

다음은 SELECT 이론이 SQL에서 적어도 이론적으로 작동하는 방법입니다. 실제 제품은 가능한 한 최적화합니다.

FROM 절에서 시작하여 모든 조인, 공용체, 교차점 및 기타 테이블 생성자가있는 작업 테이블을 작성하십시오. AS 옵션을 사용하면이 작업 테이블에 이름을 부여한 후 나머지 포함 쿼리에 사용해야합니다.

WHERE 절로 이동하여 기준을 통과하지 않는 행을 제거하십시오. 즉, 참으로 테스트하지 않습니다 (알 수 없음 및 거짓을 거부 함). WHERE 절은 FROM 절의 작업에 적용됩니다.

선택적 GROUP BY 절로 이동하여 그룹을 작성하고 각 그룹을 단일 행으로 줄이면 원래 작업 테이블이 새 그룹화 된 테이블로 바뀝니다. 그룹화 된 테이블의 행은 그룹 특성이어야합니다. (1) 그룹화 열 (2) 그룹에 대한 통계 (예 : 집계 함수) (3) 함수 또는 (4)이 세 항목으로 구성된 표현식.

선택적 HAVING 절로 이동하여 그룹화 된 작업 테이블에 적용하십시오. GROUP BY 절이없는 경우 전체 테이블을 하나의 그룹으로 취급하십시오.

SELECT 절로 이동하여 목록에서 표현식을 구성하십시오. 이는 SELECT의 스칼라 서브 쿼리, 함수 호출 및 표현식이 다른 모든 절이 완료된 후에 수행됨을 의미합니다. AS 연산자는 SELECT 목록의 표현식에도 이름을 지정할 수 있습니다. 이 새로운 이름은 한 번에 존재하지만 WHERE 절이 실행 된 후에 나타납니다. 이러한 이유로 SELECT 목록 또는 WHERE cluase에서 사용할 수 없습니다.

중첩 된 쿼리 표현식은 C, Pascal, Algol 등과 같은 블록 구조 언어에서 예상되는 일반적인 범위 지정 규칙을 따릅니다. 즉, 가장 안쪽 쿼리는 포함 된 쿼리에서 열과 테이블을 참조 할 수 있습니다.

이는 SELECT가 GROUP BY보다 많은 열을 가질 수 없음을 의미합니다. 그러나 확실히 더 적은 열을 가질 수 있습니다.

이제 Celko는 이전 버전의 표준에 대한 주요 기여자 중 하나였습니다. 당신이 WHY?추측을 제외하고는 그 질문에 대한 확실한 대답을 얻을 수 있을지 모르겠습니다 . 내 생각에 실제 작업을 먼저 나열하면 파서가 작업 유형을 정확히 알기가 매우 쉽습니다. 20- 테이블 조인이 SELECTor 또는 UPDATEor DELETE일 수 있다고 상상해보십시오. 이 엔진의 코드는 원래 문자열 구문 분석이 비용이 많이 들었던 시절에 다시 쓰여졌다는 것을 기억하십시오.

SQL 표준 FROM이 우선적으로 지시 된 경우 , 벤더는 독립적으로 문법을 다른 순서로 구문 분석하기로 결정했을 수 있습니다. 시간.

같은 것들에 대해서도 마찬가지입니다 CASE. 예를 들어, 순서와 단락으로 항상 처리 되는 이전에 믿었던 신화 가 잘못된 경우와 같이이 사이트 에서 시나리오를 보았습니다CASE . 그리고 이것은 작성된 순서대로 조인을 평가하는 SQL Server, 왼쪽에서 오른쪽으로 단락 단락WHERE 또는 CTE를 여러 번 참조하더라도 한 번 또는 특정 순서로 처리하는 것과 같은 다른 일반적인 신념으로 확장됩니다 . 쿼리가 선언적으로 작동해야한다고 명시한 방식을 정확하게 반영하지 않더라도 제품은 제품의 적합성을 자유롭게 최적화 할 수 있습니다.


2
또한 쿼리의 다른 부분에서 별칭을 사용하거나 사용하지 않는 기능은 최적화 프로그램이나 실행 엔진이 아닌 파서에 의해 적용됩니다. 엔진이 실제로 쿼리를 실행하는 방식에 구문에 영향을 미치는 제한 사항이 반드시 반영되는 것은 아닙니다.
Aaron Bertrand

2

Entity SQL 에서는 일부 상황에서 쿼리의 다른 위치에있는 표현식의 별명을 사용할 수 있습니다.

select k1, count(t.a), sum(t.a)
from T as t
group by t.b + t.c as k1

GROUP BY절에서 표현식을 사용하려면 절에서 표현식을 정의해야합니다 SELECT.

분명히 가능 앨리어스로 재사용 표현 SQL 쿼리에서 이런 종류의 일부를 허용 할 수 있습니다.

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