Laboratory/MSSQL

Tip. SQL 2005 에서 달라진것들

theking 2008. 3. 21. 19:52

[출처 : 데브피아]

김정선

Microsoft SQL Server MVP

 

1. SQL Server 2005 GROUP BY 구문 변경 

 

 SQL Server 2005에서 변경된 구문들을 몇 가지 살펴보고자 합니다.

 

그 첫 번째로 바로 얼마전에 알게된, GROUP BY 입니다.

BOL이나 문서의 언급이 없어서 참 당황스러운 결과였습니다.

 

 Itzik (SQL Server Magazine 저자, Inside SQL Server 2005 필자)에게 문의를 한 결과

변경된 사실을 최종 확인했습니다.

 대신에, 정확히 어떻게 바뀌었다는 것에 대해서는 상세 자료가 없습니다.

간단히 정리해 드리면,

 

 - GROUP BY 절에 칼럼을 포함한 수식을 적용해서, 수식의 결과를 기준으로 만들 수 있고,

 - SELECT 절의 결과 집합을 그 수식과 달리 변형해서 처리하는 것이 가능해 졌다.

 

입니다.

 

아래 예제를 직접 실행하셔서 확인해 보시면 됩니다.

-- 아래와 같은 코드는 2000, 2005 모두 가능

SELECT ISNULL(CONVERT(CHAR(7), OrderDate, 120), '')

 , COUNT(*) AS 'OrderCount'

FROM Northwind.dbo.Orders

GROUP BY OrderDate

 

 

-- 아래 코드는, 2000에서 안됨

SELECT ISNULL(CONVERT(CHAR(7), OrderDate, 120), '')

 , COUNT(*) AS 'OrderCount'

FROM Northwind.dbo.Orders

GROUP BY CONVERT(CHAR(7), OrderDate, 120)

 

 

2. SQL Server 2005 Table Hint의 WITH 키워드 구문 변경

 

힌트(Hint) 많이 쓰시나요?, 다른 건 몰라도 NOLOCK(혹은 ReadUncommitted)은 많이 쓰시죠?

 

FROM table_source WITH (table_hint, ...n)

 

 

 2000에서는 WITH 키워드가 옵션이었죠! 역시나 귀차니즘으로 인해 생략하고 사용하는 경우가

대부분이었습니다. 그러다 보니 너무 많이 생략해서 문제가 되는 경우도 있었습니다.

( 괄호까지 생략해 버렸다는...그럼, 어떻게 될까요?  ^^; )

 

 2005에서 WITH 절에 강제 사항이 붙었습니다. 굳이 문법적인 내용이 아니더라도

너무 생략해서 쓰시는 습관은 좋지 않죠?

 

어떤 경우가 실제 문법적으로 문제가 되는지 한 번 보실 필요가 있습니다.

아래 예제 코드를 실행하고, 비교해 보시구요,

더 자세한 내용은, 온라인 설명서의 sp_dbcmptlevel 와 테이블 힌트를 참조하십시오.

  

참고.

 Hint의 번역이 2000의 "참고"에서, 2005의 "힌트"로 변경된 것으로 보입니다.

 한글 번역이 많이 바뀐 거 아시죠?

 더 좋아진 내용이 많았으면 하는 개인적인 바램입니다...아~ 걱정, 걱정

 

 

예제. 

-- 1.

-- 하나의 Hint만 사용하는 경우

-- 2000, 2005: OK

SELECT TOP 5 *

FROM Northwind.dbo.Orders (READUNCOMMITTED)

 

 

-- 2-1.

-- Hint를 다른 옵션과 함께 사용하는 경우, 반드시 WITH 키워드를 사용해야 합니다.

-- 2000: OK, 2005: Error

SELECT TOP 5 *

FROM Northwind.dbo.Orders (INDEX(0), READUNCOMMITTED)

 

메시지 1018, 수준 15, 상태 1, 줄 2

'INDEX' 근처의 구문이 잘못되었습니다. 테이블 힌트의 일부인 경우에는 WITH 키워드 및 괄호가 필요합니다. 적합한 구문은 SQL Server 온라인 설명서를 참조하십시오.

 

 

-- 2-2.

-- 두 개의 Hint를 사용하는 경우 (WITH 지정)

-- 2000: OK, 2005: OK

SELECT TOP 5 *

FROM Northwind.dbo.Orders WITH (INDEX(0), READUNCOMMITTED)

 

 

3. SQL Server 2005 Order By절 구문 변경

 

 SQL Server 2000의 ORDER BY 절에서는 모호함이 많이 있었습니다. 이것이 제약없는 쿼리를

사용할 수 있다는 편리함을 주기도 하지만, "데이터 일관성"의 대명제를 가진 DB에서는 옳지 못한

구현이죠.  

 

 SQL Server 2005의 ORDER BY 는 그러한 모호함을 줄이고자 노력한 흔적이 보입니다.

아래 예제를 통해서, 2005에서 달라진 구문 제약 능력을 보시기 바랍니다.

 

 더불어, 혹여 모르고 있었을만한 2000의 문제에 대해서도 알아보는 시간이 될 수 있습니다.

  

예제. 

-- BOL 예제

USE tempdb;

CREATE TABLE SampleTable(c1 int, c2 int);

GO

 

-- SELECT 절에서 c1 이라는 별칭이 중복된다.

-- 2000: OK, 2005: Error

SELECT c1, c2 AS c1

    FROM SampleTable

    ORDER BY c1;    -- c1이 중복되므로...

GO

 

    -- 오류 발생

    메시지 209, 수준 16, 상태 1, 줄 2

    열 이름 'c1'이(가) 불확실합니다.

 

 

-- 테이블 이름(별칭)과 함께, 칼럼 별칭을 사용한 경우

-- 2000: OK, 2005: Error

SELECT c1 AS x

    FROM SampleTable

    ORDER BY SampleTable.x; -- 해당 열이 없으므로

GO

    -- 오류 발생

    메시지 207, 수준 16, 상태 1, 줄 3

    열 이름 'x'이(가) 잘못되었습니다.

 

 

-- 2000: 테이블 별칭 p가 무시되고 수식 UnitPrice에 대해서 정렬됨

-- 2005: 칼럼 UnitPrice에 대해서 정렬됨

SELECT TOP 5 ProductID

    , UnitPrice = UnitPrice * (-1)

    , UnitPrice AS U

FROM Northwind.dbo.Products p

ORDER BY p.UnitPrice

 

 

 

 

4. SQL Server 2005 T-SQL Outer Join 미지원

 

 "SQL Server 2005에서는 T-SQL 외부 조인(*=, =*) 연사자를 지원하지 않습니다,

  OUTER JOIN 키워드를 사용하거나, 혹은 DB를 2000 호환 버전 상태로 사용해야 합니다."

 

 이미 많이 알려진 내용이라 잘 아실거라 짐작되지만, 역시 그렇지 않은 분들도 많이 계실 것이므로

여기에도 소개를 합니다.

 

 SQL Server에서 사용할 수 있는 조인 문법은 크게 두 가지 버전이 있습니다.

ANSI 표준 구문 형식과, T-SQL 조인 구문(흔히 Old-style이라고도 부르는) 이 그것입니다.

이 중에서 특히 현업에서 많이 볼 수 있는 것이 T-SQL 조인 구문입니다.

 

 이미 오래전부터 ANSI 표준 구문 사용을 권장했음에도 불구하고, 여러가지 이유로 인해서 여전히

Old-style을 사용하는 분들이 많이 계시죠.

 예전 세미나에서, "특정 패키지가 모두 T-SQL 외부 조인을 사용하고 있는데 2005로 업그레이드를 하면

어떻게 해야 하느냐?" 는 질문을 받으적도 있었습니다...상당히 부담스러운 상황이죠?

 

(SQL Server 게시판에 Q/A를 검색해 보시면 참 많은 이슈들을 보실 수 있습니다.) 

 

 특히 Outer Join(외부 조인)의 경우, 그 두 가지 버전의 결과가 달라지므로 인해서 불평을 하시는

경우도 있었습니다. 실제로 술 자리에서 한 시간동안 토론을 벌인 적도 있습니다.

(하여튼 술 만 들어가면 이 놈의 직업 이야기... *^^*)

 

  이제는 오랜된 얘기라 여기서 다 풀지는 않겠습니다. 과거 자료를 참조해 보시구요,

물론 앞으로도 2000의 코드는 많이 사용될 겁니다만. 2005부터는 사용할 수도 없겠되었지만,

(옵션을 변경해서라도) 사용하지 않는 것이 좋겠습니다!

(차기 버전에서는 옵셔으로도 지원이 안될 수 있으니까요 ^^;)

 

 아래 간단한 예제를 올립니다. 도움이 되시길...

 

예제. 

USE Northwind

go

 

-- 호환성 수준 확인

sp_dbcmptlevel 'northwind'

 

    현재 호환성 수준은 90입니다.

 

-- equal join?

SELECT TOP 5 *

FROM Orders om , [Order Details] od

WHERE om.OrderID = od.OrderID

go

 

-- outer join?

SELECT TOP 5 *

FROM Orders om , [Order Details] od

WHERE om.OrderID *= od.OrderID

go

 

    메시지 4147, 수준 15, 상태 1, 줄 3

    쿼리에서 ANSI 형식이 아닌 외부 조인 연산자("*=" 또는 "=*")를 사용합니다. 이 쿼리를 수정하지 않고 실행하려면 저장 프로시저 sp_dbcmptlevel을 사용하여 현재 데이터베이스의 호환성 수준을 80 이하로 설정하십시오. 가장 좋은 방법은 ANSI 외부 조인 연산자(LEFT OUTER JOIN, RIGHT OUTER JOIN)를 사용하여 쿼리를 다시 작성하는 것입니다. SQL Server의 다음 버전에서는 ANSI 형식이 아닌 조인 연산자는 역호환성 모드에서도 지원되지 않습니다.

 

-- 80버전으로 수정하면?

sp_dbcmptlevel 'northwind', 80

sp_dbcmptlevel 'northwind'

 

    현재 호환성 수준은 80입니다.

 

    -- outer join?

    SELECT TOP 5 *

    FROM Orders om , [Order Details] od

    WHERE om.OrderID *= od.OrderID

    go

 

 

sp_dbcmptlevel 'northwind', 90

 

 

 

 

5. SQL Server 2005 숫자 변환이 일어나지 않는다.

 

 "숫자 유형이 변환하지 않고 비교됩니다. 따라서 성능이 향상됩니다.

  그러나 이런 경우 동작이 약간 변경될 수 있습니다.

  특히, 변환으로 인해 오버플로 예외가 발생하는 경우에 더욱 그렇습니다."

 

"SQL Server 2000 버전까지는

숫자 유형(smallint, tinyint, int, bigint, numeric, decimal, smallmoney, money) 간 비교는

유형 계층에서 우선 수위가 낮은 피비교수를 우선 순위가 높은 유형으로 변환하여 수행합니다."

 

 이러한 변화는 크게 두 가지 의미에서 그 중요성을 고려해야 합니다. 첫 번째는 데이터 비교 동작 시의

발생할 수 있는 오류 즉 정확성에 대한 문제. 두 번째는 - 사실은 가장 관심 있는 - 성능 문제입니다.

 

 직접적인 예를 들어보시죠. 아래의 WHERE절에 사용된 검색 조건식이 성능 문제를 가지고 있다고

가정을 합니다. 어떤 문제가 있을까요?

  

 SELECT select-list FROM table_source
 WHERE Column = 1  

  

 이 글을 읽는 분들 중에 상당 수는 관계형 데이터베이스의 SARG(Search ARGument)에 대해서 알고

계시리라 짐작됩니다-혹 모르신다면 반드시 공부하십시오. 그 중에서도 암시적 형 변환으로 인한

SARG의 위반은 사용자의 눈에 잘 드러나지 않는다는 어려움을 가지고 있으면서도 성능에 큰 영향을

미칩니다.

 

 위 쿼리에서 Column 이 문자 타입(char, varchar, 등)이라면 문자 = 숫자 형 간의 비교가 요구되고,

이를 해결하기 위해서 위에서 언급된대로 우선 순위가 낮은 문자 타입를 숫자 형으로 변환하는

중간 과정에서 암시적 형 변환이 일어나는 것입니다.

 

 SQL Server 2005에서 SARG에 대한 Optimizer의 동작에 변화가 보입니다. 그 한 가지가 바로 지금

다루고 있는 암시적 형 변환입니다. 물론 대부분이 좋은 결과를 가져오지만, 여전히 문제가 되는 부분도

있습니다.

 

  암시적 형 변환은 데이터 형에 따라서 그 동작과 결과가 달라집니다.

 우선 그 중 한가지, 바로 숫자형에 대한 변환 동작입니다. 이 글의 처음에 주지한대로

SQL Server 2005에서는 숫자 형 간의 변환이 일어나지 않는다는 것입니다.

 

 참고. BOL에서 언급된 내용에는 약간의 오류가 있을 수 있습니다. 숫자형 데이터는 종류가 많은데도

     워낙 광범위한 표현을 쓰고 있기 때문입니다. 따라서 각각의 상황은 달라질 수 있습니다.

 

 SARG를 알고 계신다면, SQL Server 2005에서 SARG가 어떻게 변화되었는지에 대해서 자세히

살펴보실 필요가 있으실 겁니다. 이것은 그 중 하나의 포함된 또 하나의 작은 내용일 뿐입니다.

(차후에 그 변화에 대해 전반적으로 소개하는 기회가 있을 것입니다)

 

 간단하지만 아래 예제를 통해서 우선 이 주제를 살펴보시기 바랍니다.

 도움이 되시길...

 

 

예제. SQL Server 2000 

USE Northwind

go

 

/*

   SQL 2000

*/

SET SHOWPLAN_TEXT ON

GO

-- 숫자값 간의 변환이 일어나지 않는다.

SELECT *

FROM northwind.dbo.orders

WHERE orderid = 1.0

GO

 

 -- 아래는, SHOWPLAN_TEX로 인한 출력 결과. WHERE 조건의 Convert()를 볼 수 있다.

 

  |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1002], [Expr1003], [Expr1004]))

       |--Compute Scalar(DEFINE:([Expr1002]=Convert([@1])-1, [Expr1003]=Convert([@1])+1, [Expr1004]=If (Convert([@1])-1=NULL) then 0 else 6|If (Convert([@1])+1=NULL) then 0 else 10))

       |    |--Constant Scan

       |--Clustered Index Seek(OBJECT:([Northwind].[dbo].[Orders].[PK_Orders]),SEEK:([Orders].[OrderID] > [Expr1002] AND [Orders].[OrderID] < [Expr1003]),  WHERE:(Convert([Orders].[OrderID])=[@1]) ORDERED FORWARD)

 

 

SET SHOWPLAN_TEXT OFF

 

 

 

예제. SQL Server 2005 

USE Northwind

go

 

/*

   SQL 2000

*/

SET SHOWPLAN_TEXT ON

GO

-- 숫자값 간의 변환이 일어나지 않는다.

SELECT *

FROM northwind.dbo.orders

WHERE orderid = 1.0

GO

 

 -- 아래는, SHOWPLAN_TEX로 인한 출력 결과. Convert()가 일어나지 않고, SEEK 조건을 만족한다.

 

  |--Clustered Index Seek(OBJECT:([Northwind].[dbo].[Orders].[PK_Orders]),SEEK:([Northwind].[dbo].[Orders].[OrderID]=[@1]) ORDERED FORWARD)

 

 

SET SHOWPLAN_TEXT OFF

 

  

 

6. SQL Server 2005 ISNUMERIC() 함수에서 쉼표(,)를 무시한다.

 

 "SELECT ISNUMERIC('<string>')에서 <strin>내에 포함된 쉼표는 무시됩니다.  

   따라서 숫자로 인정될 수 있습니다."

 

 이번 내용은 간단합니다. 말 그대로 쉼표를 숫자 형식에서 무시한다는 것이죠.

따라서 ISNUMERIC() 이 1을 반환합니다.

 

SQL Server 2000에서는 쉼표를 포함한 경우 숫자 형식이 아닌 것으로 취급, 0을 반환합니다.

 

아래 그 예제를 보겠습니다.

 

예제. ISNUMERIC() 함수 

SELECT ISNUMERIC('121212,12')   -- 숫자 (2000은 0)

 

-----------

1

 

(1개 행 적용됨)

 

  

 그런데 온라인 설명서의 언급하고 있는 내용에 문제가 있어 보입니다.

 

"반환 값이 1인 경우에는expression을 적어도 이러한 숫자 형식 중 하나로 변환할 수 있습니다."

 라고 언급합니다. 그렇다면, 일반적인 변환 방법으로 가능할까요? 아니면 특별함 방법을 써야할까요?"

  

예제. 숫자 형식 변환 작업 

SELECT CAST('121212,12' AS int)

-- SELECT CONVERT(INT, '121212,12')

 

-----------

메시지 245, 수준 16, 상태 1, 줄 1

varchar 값 '121212,12'을(를) 데이터 형식 int(으)로 변환하지 못했습니다.

 

  

 SQL Server 2000에서 쉼표를 사용하지 않았으므로, 2005로 변환 시 문제의 소지는 없겠지만 새로운 개발에서 사용자의

실수가 포함된다면 문제 발생의 원인이 될 수도 있겠지요.

 

차후에 정확한 내용이 규정되리라 기대합니다.