ORM(Object Relational Mapping), ADO.NET 3.5, LINQ, LINQ to SQL 그리고 ADO.NET Entity Framework 이런 용어들은 일반적인 DBA에게 매우 낮 설은 용어들일 것 입니다. 이는 Visual Studio 2008과 함께 새로 제공되는 ADO.NET 3.5의 이전까지 없었던 단일 개념으로는 가장 대규모의 변화로 느껴집니다. LINQ 는 현재 Visual Studio 2008에 중요한 화두가 되어 있으며, 많은 개발자들이 상당한 관심을 보이고 있습니다. 그 중에서도 LINQ to SQL은 논쟁의 중심에 있습니다. 실제로 Visual Studio 관련된 세미나와 자료 등에서 LINQ와 LINQ to SQL이 핵심 주제 중의 하나로 다루어지고 있는 것을 알 수 있습니다. 저 또한 그러한 세미나를 통해 다른 전문가들의 의견을 들어 보고 있습니다.
Microsoft ADO.NET팀을 포함해서 많은 개발자들이 LINQ, LINQ to SQL에 대해서 침이 마르도록 그 장점과 이득을 강변하는 것을 들을 수 있습니다. 물론 저 또한 상당 부분 동의를 합니다. 그러나 오늘은 개발자로서의 관심사가 주제가 아닙니다. SQL Server를 관리하는 DBA 입장에서 LINQ to SQL이 어떻게 다가올 지 약간의 염려와 함께, DBA로서 바라보는 시각이 어떤 것인지, 무엇에 관심 있는 지, 그리고 앞으로 어떻게 다루어야 할지에 대한 작은 고민을 해 보고자 합니다.
ORM, LINQ to SQL, Entity Framework 등등, 그 안에서 무슨 일이 벌어지고 있던 DBA에겐 관심 없는 영역입니다. Application 혹은 Service를 무엇으로 어떻게 구현하든, ORM를 어떻게 현실화하건 결국 SQL Server에 요청되는 명령은 SQL입니다. 따라서 DBA에게 관심 있는 것은 LINQ to SQL이 아니라, LINQ to SQL에 의해서 호출되는 바로 그 쿼리에 해당하는 것이죠.
특히, 그 중에서도 가장 관심 있는 영역은 바로 그 쿼리의 성능 문제입니다. DBA로서 당연한 관심사입니다. 이 글을 읽는 분이 DBA 가 아니시라면, DBA의 시각과 그들의 관심사를 이해하는 목적으로 보시면 좋겠습니다. 나중에 또 티격태격 싸우지 않으시려면……^^
DBA를 위한 LINQ to SQL 소개
LINQ(Language INtegrated Query) 및 LINQ to SQL을 모르는 DBA를 위한 주제이므로 간단히 소개부터 하겠습니다. 직접 개발할 것은 아니므로, 그 구현 단계까지 상세하게 설명할 필요는 없을 것 같습니다. 그저 아~ 이런 것이구나? 라고 느낄 정도면 충분할 듯 합니다. 핵심만 간단히 정리하고 참고 자료로 마무리하겠습니다.
간단히 두 버전을 비교해 보면 쉽게 이해할 수 있습니다. 우선 LINQ to SQL을 사용하기 이전의 일반적인 ADO.NET 코드 그리고 LINQ to SQL을 사용한 코드 예제입니다.
[그림. 일반적인 ADO.NET 코드 예제]
[그림. LINQ to SQL 예제]
두 예제 코드의 차이점이 보이는지요?
결론만 얘기하자면, 바로 SQL을 구현하는 방법의 차이입니다. 즉, 이전엔 흔히 하드 코딩된 쿼리 혹은 Adhoc 쿼리라고 부르던 방식입니다. 말 그대로 프로그램 코드 안에 SQL 쿼리를 직접 작성해서 입력하는 방식이죠. 반면에 LINQ to SQL은 직접 쿼리를 작성하지 않습니다. LINQ to SQL Class Model과 ORM Framework을 통해서 구현된 class에 대해 LINQ 문법을 이용해서 코드를 작성하면 실행 시 실제 SQL 쿼리가 Framework에 의해서 자동 구현되고 호출되는 것입니다. 아마 이를 처음보시는 분은 엥? 문법이 왜 저래? 왜 거꾸로 된 거야? 라고 황당해 하는 분들이 대부분이실 겁니다. 이건 상상해 맡기겠습니다. ^^
보시고 무슨 생각이 드시나요? 매우 좋아 보이시나요? 혹시 무언가 염려스러운 부분은 없습니까?
그럼, 저희들의 관심사를 확인해 보죠. LINQ 문법과 Framework에 의해서 실제로 SQL Server로 호출되는 쿼리는 어떤 모양을 가지고 있을까요? 현재 LINQ는 기본적인 SQL 문법을 상당 부분 지원하고 있습니다. 즉 단순한 SELECT 뿐만 아니라, WHERE, ORDER BY, GROUP BY, JOIN 등의 해당하는 LINQ 문법을 모두 지원합니다. 심지어 게시판 형태의 Paging 구현 작업에 사용될 수 있는 Skip(), Take() 등의 메서드를 이용하면, ROW_NUMBER(), TOP 과 같은 쿼리들도 구현이 됩니다.
그럼, 그 중에서 JOIN, JOIN과 GROUPING, 그리고 앞서 소개한 Paging 작업에 대한 LINQ to SQL 구현 예제와 함께 실제로 어떤 쿼리가 생성되고 호출되는지 Profiler를 통해 추적과 결과를 보여드리도록 하겠습니다. 실제 쿼리를 보시면 어떻게 처리되고 있는지 금방 짐작하실 수 있으실 겁니다.
우선 아래 그림은 Visual Studio 2008의 LINQ to SQL 디자이너를 이용해서 만든 class 모델입니다.
Northwind 데이터베이스의 세 개의 테이블을 가지고 있고, 각각 조인 및 집계 작업으로 아래 예제에서 구현될 것입니다.
[그림. LINQ to SQL 디자이너 화면]
[그림. JOIN]
[그림. JOIN – 실제 쿼리]
[그림. JOIN과 GROUPING, 집계]
[그림. JOIN과 GROUPING, 집계 – 실제 쿼리]
[그림. Paging]
[그림. Paging – 실제 쿼리]
무엇이 문제인가?
LINQ to SQL Framework에 의해서 생성된 쿼리들을 보셨습니다. 어떤 특징들이 보이는지요? Adhoc 쿼리가 아니라, sp_executesql를 이용한 Prepared 타입의 쿼리로 호출되고 있습니다. 이것이 평균적으로 좋은 선택인가요? 혹시 반대 의견은 없으십니까?
쿼리는 마음에 드십니까? 성능은 어떨 것 같습니까? 적절한 성능의 쿼리라고 판단되시는지요? 여러 분이 직접 작성하신 다면 위와는 다르게 작성하시겠습니까?
만일 저 쿼리가 악성 쿼리가 된다면 혹은 어떤 이유로든 쿼리를 바꾸고 싶다면 어떻게 하시겠습니까? 만일 LINQ to SQL Framework에 의해서 생성된 특정 쿼리를 바꿀 수 없다면 그 땐 어떻게 하시겠습니까?
물론 LINQ to SQL이 저장 프로시저를 지원합니다. 그럼 LINQ to SQL에 저장 프로시저를 연동하면 되겠군요. 과연 LINQ to SQL을 사용하면서 저장 프로시저까지 쓸려고 할까요? 만일 저장 프로시저를 사용하지 않는다면요? 그 땐 또 어떻게 대처하시겠습니까?
앞으로의 숙제이자 논쟁거리로 남겨놓겠습니다. 실제로 현업에서 어떻게 구현될지는 지켜봐야 하니까요. 제가 주로 하는 일이 SQL Server 성능 튜닝이므로, 당연히 아주 관심이 많습니다.
참고. Paging 구현을 지원하는 코드 및 ROW_NUMBER()를 포함한 내부 쿼리를 보고 이것이 최적화된 쿼리이므로 매우 성능이 우수할 것으로 보는 개발자 분들이 많이 계십니다만, 저는 그렇게 보지 않습니다. 대용량 데이터베이스에선 분명히 해당 쿼리를 진단하고 튜닝을 해야 할 것으로 보여집니다.
아참, ADO.NET Entity Framework이라는 것도 있습니다. 엔터프라이즈 환경에선 더 많이 사용될 것으로 전망하고 있던데요, 여기선 또 ESQL이라는 문법을 사용합니다. 근데 이게 또 아주 재미있습니다. 쿼리에 관한 한 더 많은 이슈가 있을 듯 합니다.
마치면서
외국의 경우 LINQ to SQL과 Entity Framework에 대해서 Microsoft, ADO.NET팀, 개발자 진영과 DBA 진영 간의 상당한 논쟁을 계속하고 있습니다. 제가 지난 2007년에 Denver에서 열린 PASS 행사에 참여했을 때도 SQL MVP 전용 세션에서 발표를 나온 ADO.NET 팀 멤버 한 명이 전체 MVP들을 대상으로 1대 다의 대결 구도를 보여주었었습니다.
SQL Server 개발 영역의 전문가 중의 한 명으로, “SQL Server 2005 Developers Guide”의 저자인, Bob Beauchemin이 자신의 블로그를 통해 LINQ to SQL및 Entity Framework에 대한 염려와 고민들을 올려 놓았습니다.
댓글 영역