2009/05/06 18:42

SqlParameter 쓸 때 주의해야 할 점


위에 그림은 두 쿼리문의 실제실행계획입니다.
쿼리문은 동일한데 첫번째의 경우는 뭔가 매우 복잡한 과정을 거치고 있습니다.
과연 어떤 차이가 있을까요?

실제로 실행시킨 두 쿼리문은 다음과 같습니다.

exec sp_executesql N'select [Buffer] from [Thumbnail] where [ID]=@ID',N'@ID nvarchar(36)',@ID=N'274E13CB-F01A-4924-801D-46A853792A69'

exec sp_executesql N'select [Buffer] from [Thumbnail] where [ID]=@ID',N'@ID char(36)',@ID=N'274E13CB-F01A-4924-801D-46A853792A69'

두 쿼리문의 차이점을 찾으셨나요?
첫번째 쿼리문은 nvarchar(36)으로 parameter 타입이 정의되어 있고, 두번째 쿼리문은 char(36)으로 타입이 정의되어 있습니다.
눈치채셨겠지만 "ID"열은 char(36)으로 타입이 지정되어 있습니다.

위 쿼리문은 ADO.NET을 이용해서 다음과 같이 프로그래밍 했을 때 SQL 서버로 전달되는 쿼리문입니다.

string query = "select [Buffer] from [Thumbnail] where [ID]=@ID";
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.Add(new SqlParameter("@ID",  "274E13CB-F01A-4924-801D-46A853792A69"));

이런식으로 프로그래밍 되어 있을꺼라고 쉽게 유추해볼 수 있습니다.
하지만 이렇게 되어 있을 경우에 첫번째 쿼리문처럼 nvarchar로 타입이 지정되게 됩니다.
따라서 위의 그림처럼 불필요한 컨버팅 과정을 거치게 되는 것입니다.
게다가 찾기 조건자도 다음과 같이 구성이 됩니다. 그리고 실행계획에는 분명 Clustered Index Seek를 한다고 되어있지만 프로파일링을 해보면 Index Scan이나 Table Scan을 하는 것처럼 Page 읽는 횟수가 어마어마합니다.

Start: [APPARELBASE].[dbo].[Thumbnail].ID > Scalar Operator([Expr1005]), End: [APPARELBASE].[dbo].[Thumbnail].ID < Scalar Operator([Expr1006])

하지만 다음과 같이 SqlDbType도 지정을 해주면 두번째 처럼 원하는 결과를 얻을 수 있습니다.

string query = "select [Buffer] from [Thumbnail] where [ID]=@ID";
SqlCommand command = new SqlCommand(query, connection);
SqlParameter parameter = new SqlParameter("@ID", SqlDbType.Char, 36);
parameter.Value = "274E13CB-F01A-4924-801D-46A853792A69"

command.Parameters.Add(parameter);

즉, 결론은 SqlParameter를 써서 프로그래밍 할때는 꼭 SqlDbType을 지정해주자는 야그입니다.
하긴 DB 쿼리문도 문제가 많더라.... 그거는 언제 고치냐... 이런 고민거리도 쌓이고 쌓였습니다. OTL
Trackback 0 Comment 0