Hyun Soo, Lim

NDC 2012 행사기간에 발표했던 자료 공유합니다. 그동안 블로깅했던 내용 중 SQL Server 2012에서 향상된 프로그래밍 기능을 간략히 정리해보았습니다.

상세 테스트 스크립트와 내용정리는 "[펌/정리]SQL Server 2012 (Denali) 신기능" 글의 링크를 통해서 보실 수 있습니다.

 

 

SQL Server 언플러그 세미나 - 토크쇼 때 이야기나누었던 내용 간략히 정리하여 공유드립니다.

 

이야기드리고자 했던 내용은 아래와 같습니다.

  1. 고가용성 시스템 구축시 기술에 대한 깊이 있는 검토/테스트 필요 (장단점 비교 분석)

      - 안정성을 높이기 위한 기술인데 이로 인하여 문제가 발생하면 안되겠죠.~

  2. DB 시스템보다는 서비스 측면에서의 고민 필요

 

간략히 PT와 SQL Server 2012의 고가용 기능에 대한 테스트 동영상 올립니다.

 

[SQL Server 2012 AlwaysOn Availability Group]

 

 

 

 

 

 

NDC 2011 발표 자료 공유드립니다. 게임 DB 성능 향상을 위해 고민해보았으면 하는 내용을 정리해보았습니다.
게임 관련하여 관심 있으신 분은 NDC 2011 사이트 방문하셔도 좋을 듯 합니다.

 

프레젠테이션을 할 때 예제 스크립트를 보여주는 경우가 있는데, 이런 경우에 사용하면 유용할 것 같아서 공유드립니다.
확대가 가능한 부분은 "쿼리창/Message 영역/실행계획" 입니다. "결과창"은 줌 기능이 동작을 안하네요.



출처. http://blog.sqlauthority.com/2011/03/20/sql-server-denali-feature-zoom-query-editor/

이번 글에서는 SQL Azure에 대해서 간단하게 접속, 사용방법을 소개해드리고자 합니다. SQL Azure에 대한 개인적인 느낌이나 생각에 대해서는 좀 더 사용해보고 다음 번 글에서 공유 드리겠습니다. 무료 계정이 제공되어지고 있으니 관심 있으신 분들은 한번 사용해보시는 것도 좋을 듯 합니다.

*. 소개
SQL Azure란 Microsoft SQL 서버 2008 기술을 기반으로 최초의 클라우드 기반의 자기 관리되는 관계형 데이터베이스 서비스를 이야기합니다.

*. 가입하기
아래의 블로그에 가시면 1달 무료 이용코드가 공유되어있습니다. 해당 코드를 가지고 무료 가입이 가능합니다.

가입하면 메일을 받고 2~3일정도 뒤에 메일로 승인 완료 메일이 옵니다. (DNS 셋팅 때문에 시간이 걸리는 듯 합니다.)


*. Management Portal 접속하기
1. Management Poral 접속화면
   

2. 본인이 소유한 서버에 접근하여 서버 정보 및 속성을 확인하는 화면
   

3. 데이터베이스 생성하기 화면 ("create" 버튼 클릭, Edition에는 web과 business가 존재함.)
   

4. 데이터베이스 생성 완료 후 확인 (변경된 내용 확인시 "Refresh" 후 확인 가능함)
   

*. Database Manager 사용해보기
1. "Manage" 버튼을 클릭하면 로그인 창이 뜹니다. 암호를 넣고 로그인하면 아래와 같은 첫화면이 뜹니다.
    StartPage에서 현재 데이터베이스의 설정과 디스크 사용현황 등을 보여집니다.
   

2. "New Query" 버튼을 누르면 쿼리창이 뜨고, 쿼리를 작성하고 실행하면 됩니다. 기본틀은 SSMS와 유사합니다.
   

*. SQL Server Management Studio 사용해보기
1. 참고사항
  - SQL Server 2008 SSMS으로는 접속이나 사용은 안되어집니다. SQL Server 2011 SSMS로 접속은 잘되어집니다. 
  - Firewall Rule에 현재 PC의 IP를 허용해야 합니다.

2. SSMS에서 접속하기
   

3. 접속한 뒤 쿼리 실행시키기
    원격 연결하여 사용하는 것과 동일하다. Object Explorer에 일부 기능이 안보인다는 점만 제외한다면~
   

*. Database Manager를 잠시 사용해보고 느낀 점은 아래와 같습니다.

 

Database manager (web)

장점

- 실버라이트로 구현되어 접근이 용이하고 가볍다.

- 언제, 어디서나 인터넷 접속만 가능하다면 기본적인 작업이 가능하다.

단점

- 예약어 표기가 안된다. (>select는 파랑색으로~)

- 쿼리 결과 내용에 대해서 복사/붙여넣기 기능 사용이 불가능하다.



 

Contained Database SQL Server Instance의 설정 중에 데이터베이스에 영향을 주는 부분을 데이터베이스 내에 자체적으로 관리할 수 있는 것을 이야기합니다. 예를 보자면 Contained Database로 설정하면 사용자 데이터베이스 내에 자체적으로 로그인 계정을 생성이 가능합니다. 이렇게 데이터베이스를 인스턴스와 독립시킴으로써 데이터베이스 이동이 쉬워졌습니다. 추가적으로 데이터베이스안에 모든 셋팅이 가능하게 됨으로써 데이터베이스 소유자가 자체적으로 관리가 가능하게 되었습니다.

 

데이터베이스 구분

데이터베이스 구분

설명

Non-contained database

Denali 이전 버전에 만들어진 데이터베이스를 이야기함.

Fully contained database

아직은 제공되어지지 않음.

Partially contained database

일부 기능만 제한적으로 제공함.

 

Contained Database 사용시 활용적 측면과 주의사항

항목

설명

활용적 측면

1. 인스턴스 간에 데이베이스 이동이 원활한다.

- 연결된 서버, 시스템 셋팅, Application level agent jobs, 로그인

2. Application 개발

- 인스턴스의 환경적인 요소에 제한을 받지 않는다.

3. Application 관리

주의사항

1. 다른 데이터베이스에 guest 계정 접근이 허용된 경우 Contained database로 접근한 뒤 다른 데이터베이스로 이동이 가능한다.

2. 동일한 이름의 중복 로그인 계정이 생성되어짐으로써 문제가 될 수 있다.

3. Contained database를 인스턴스 이동시킬 경우, 예기치 못한 사용자가 해당 인스턴스에 접근하게 될 수 있다.

4. Contained database의 경우 복제, change data capture, change tracking 기능을 사용할 수 없다.

 

보면서 느낀 점……

확실히 필요한 기능이라고 생각합니다. 인스턴스 간에 데이터베이스를 이동시킬 때 연결된 서버, collation, 로그인 계정 등 신경쓸 것이 많습니다. 실제 데이터베이스 이동시 신경을 쓰더라도 꼭 놓치는 부분이 발생합니다. Fully contained Database가능하게 된다면 유용할 것으로 기대됩니다.

하지만 현재 기준으로 본다면 로그인 등 일부 기능에 대해서만 제한적으로 제공되고 있어서 아직 만들고 있는 기능이라고 보입니다. 아직 완성된 기능이라는 느낌은 들지 않습니다. 서비스에 사용하실 때에는 이슈가 될 수 있는 요소에 대해서 명확한 기준을 잡고 적용하지 않으면 운영상 더 복잡해질 수 있으니 주의가 필요합니다.

 

간단히 로그인 계정을 Contained database 내에 만들 수 있도록 설정해보도록 하겠습니다.

Contained database 설정하기 (SSMS)

-- 서버 속성 설정

 


--
해당 데이터베이스 설정

 

-- 데이터베이스 내에서 로그인 계정 만들기
 
 

Contained database 설정하기 (명령어)

-- 서버 속성 설정

sp_configure 'show advanced options', 1;

GO

RECONFIGURE;

GO

sp_configure 'contained database authentication', 1;

GO

RECONFIGURE;

GO

sp_configure 'show advanced options', 0;

GO

RECONFIGURE;

GO

 

-- 해당 데이터베이스 설정

CREATE DATABASE [MyContainedDB] CONTAINMENT = PARTIAL

GO

-- 데이터베이스 내에서 로그인 계정 만들기

CREATE USER [MyContainedUser] WITH PASSWORD = '5up3r53cret'

 

참고문헌.

1.     http://msdn.microsoft.com/en-us/library/ff929071(v=SQL.110).aspx

2.     http://cm-bloggers.blogspot.com/2011/01/contained-databases-in-sql-server.html

업무를 하다보면 텍스트 파일이나 엑셀파일에 있는 데이터를 데이터베이스에 입력해야 하는 경우가 종종 있습니다. SQL Server에서는 외부 데이터를 DB에 넣기 위해서 Openquery, 데이터가져오기, bcp, SSIS 등 다양한 방식을 제공하고 있습니다.

DB 기술이 아닌 엑셀을 활용하여 insert 쿼리를 쉽게 만들 수 있는 방법이 있어 소개드리고자 합니다.

게임 아이템 10개를 등록해야 한다고 가정하고 작업 과정을 한번 정리해보겠습니다.

1. 게임 아이템 리스트를 개발팀에서 엑셀로 전달 받음
   

2. 엑셀의 CONCATENATE 함수를 사용하여 인서트 쿼리를 만든다.
   

3. 엑셀에 만들어진 insert 쿼리를 복사하여 DB에 저장한다.
  

사용하는 경우에 따라서 틀리겠지만, 제 경험상으로 보면 동일한 포맷으로 적은 건수에 대해서 빈번하게 요청이 들어오는 경우에 엑셀을 꽤 유용하게 사용했었습니다. 
이 방법은 응용하면 테이블 명세서를 바로 테이블 생성 스크립트로 만드는 것도 가능합니다. 테이블 생성 스크립트 예제는 첨부파일에 정리해놓았습니다.

[첨부] 테스트 엑셀 파일


최근에 프로젝트 진행하면서 APPLY 연산자를 적용해볼만한 사례가 있었습니다. 간단히 APPLY 연산자에 대해서 소개를 드리고, 테스트했던 내용을 보기로 하겠습니다.

BOL 내용을 바탕으로 APPLY 연산자에 대해서 간단히 소개드립니다. (BOL에서 발취)

APPLY 연산자를 사용하면 쿼리의 외부 테이블 식에서 반환한 각 행에 대해 테이블 반환 함수를 호출할 수 있습니다. 테이블 반환 함수는 오른쪽 입력이 되고 외부 테이블 식은 왼쪽 입력이 됩니다. 오른쪽 입력은 왼쪽 입력의 각 행에 대해 평가된 후 생성된 행이 조합되어 최종 출력에 표시됩니다. APPLY 연산자에 의해 생성되는 열 목록은 왼쪽 입력의 열 집합 뒤에 오른쪽 입력에서 반환된 열 목록을 추가한 것입니다.

APPLY 연산자에는 CROSS APPLY와 OUTER APPLY라는 두 가지 형태가 있습니다. 
 > CROSS APPLY는 테이블 반환 함수로부터 결과 집합을 생성하는 외부 테이블의 행만 반환합니다.
 > OUTER APPLY는 결과 집합을 생성하는 행과 그렇지 않은 행을 모두 반환하고, 테이블 반환 함수에 의해 생성된 열에는 NULL 값을 표시합니다.

APPLY 연산자 문법은 아래와 같습니다.
left_table_source { CROSS | OUTER } APPLY right_table_source
 > APPLY 연산자의 좌우 피연산자는 모두 테이블 식입니다. 이 피연산자 간의 주된 차이점은 right_table_source가 left_table_source의 열을 함수의 인수 중 하나로 사용하는 테이블 반환 함수를 사용할 수 있다는 것입니다.
 > left_table_source는 테이블 반환 함수를 포함할 수 있지만 right_table_source의 열인 인수는 포함할 수 없습니다.

 > left_table_source의 각 행에 대해 right_table_source를 계산하여 행 집합을 생성합니다.

 > right_table_source의 값은 left_table_source에 따라 달라집니다. right_table_source는 TVF(left_table_source.row)와 같이 표현될 수 있습니다. 여기서 TVF는 테이블 반환 함수입니다.

APPLY에 대해서 간단히 요약해보았습니다.

항목

내용

장점

서브쿼리와는 다르게 왼쪽 테이블의 데이터를 기준으로 오른쪽에서 개별 데이터마다 여러 행의 결과를 가지고 있음

단점

NL Join 형태로 동작하기 때문에 대량 데이터 처리 비용이 높다. Join으로 처리가 가능한 경우는 굳이 APPLY 사용하기를 추천하지 않으며, 반드시 필요한 경우에만 제한적으로 사용하기를 권장함.

특이사항

APPLY 사용하려면 데이터 베이스 호환성 수준이 적어도 90 이어야 .



그럼 이제 사례를 가지고 테스트를 진행해보도록 하겠습니다.

[구현 기능에 대한 소개]
 1. 웹 게시판의 게시물 리스트 화면을 구현합니다. (하나의 페이지는 5개의 글로 구성됨)
 2. 리스트 화면에서 각 게시물별로 최근에 등록된 댓글 3개를 추가로 보여주어야 합니다.
 3. 테스트 내용은 게시물 리스트 화면에 보여줄 글 번호를 알고 있는 상태에서 2번 항목만 구현하였습니다.
 4. 테스트는 APPLY, Rank 함수, CTE를 사용하여 진행하여 보았습니다.


[테스트 테이블 생성]
use tempdb

go

 

drop table Article

drop table Article_comment


-- 게시물 테이블 생성

create table Article (

           ArticleNo  int identity (1,1)

,          title      varchar(1000)

,          Contents   varchar(1000)

)

 

create unique clustered index idx_Article_ArticleNo on Article (ArticleNo)

 

-- 테스트 데이터 입력(게시물)

insert into Article (title, contents)

select 'title' + replicate('1', 100), replicate('1', 1000)

union all select 'title' + replicate('2', 100), replicate('2', 1000)

union all select 'title' + replicate('3', 100), replicate('3', 1000)

union all select 'title' + replicate('4', 100), replicate('4', 1000)

union all select 'title' + replicate('5', 100), replicate('5', 1000)

union all select 'title' + replicate('6', 100), replicate('6', 1000)

union all select 'title' + replicate('7', 100), replicate('7', 1000)

union all select 'title' + replicate('8', 100), replicate('8', 1000)

union all select 'title' + replicate('9', 100), replicate('9', 1000)

union all select 'title' + replicate('0', 100), replicate('0', 1000)

-- 댓글 테이블 생성

create table Article_comment (

           ArticleNo      int not null

,          commentNo      int identity(1,1)

,          contents         varchar(1000)

)

 

create clustered index idx_Article_comment_ArticleNo_commentNo on Article_comment (ArticleNo, CommentNo)

 

-- 테스트 데이터 입력 (댓글)

declare @articleNo int

 

set @ArticleNo = 0

 

while (@ArticleNo < 10)

begin

       insert into Article_comment (ArticleNo, contents)

       select @ArticleNo, replicate('1', 1000)

       union all select @ArticleNo, replicate('2', 1000)

       union all select @ArticleNo, replicate('3', 1000)

       union all select @ArticleNo, replicate('4', 1000)

       union all select @ArticleNo, replicate('5', 1000)

       union all select @ArticleNo, replicate('6', 1000)

       union all select @ArticleNo, replicate('7', 1000)

       union all select @ArticleNo, replicate('8', 1000)

       union all select @ArticleNo, replicate('9', 1000)

       union all select @ArticleNo, replicate('0', 1000)

 

       set @ArticleNo = @ArticleNo + 1

end

[테스트 데이터 확인]
select * from Article with (nolock)

select * from Article_comment with (nolock)




[CPU, IO 사용 지표 설정]

set statistics io on

set statistics time on


[APPLY 연산자를 사용한 구현]

select o.ArticleNo, o.CommentNo, o.Contents

from Article as a with (nolock)

           cross apply

           ( select top 3 b.*

                     from Article_comment b with (nolock)

                     where a.ArticleNo = b.ArticleNo

                     order by b.CommentNo desc ) as o

where a.ArticleNo in ( 1, 2, 4, 6, 9)






[CTE를 이용한 구현]
with comment_cte (articleNo, commentNo, Depth, RankNo)

as

(

           select ArticleNo, 0 commentNo, 0 as Depth, cast(0 as bigint) as RankNO

           from Article as a with (nolock)

           where a.ArticleNo in ( 1, 2, 4, 6, 9)

           union all

           SELECT b.ArticleNo, b.CommentNo, Depth + 1, RANK() over (partition by b.articleNo order by b.commentNo desc) as RankNo

    FROM dbo.Article_comment AS b with (nolock, index(idx_Article_comment_ArticleNo_commentNo ))

                     inner join comment_cte c on b.ArticleNo = c.articleNo

           where Depth = 0

)

select y.ArticleNo, y.commentNo, y.Contents

from comment_cte x

       join Article_comment y with (nolock) on x.ArticleNo = y.ArticleNo and x.CommentNo = y.CommentNo

where RankNo between 1 and 3

order by x.articleNo, x.RankNo




[Rank 함수를 이용한 구현]
select y.ArticleNo, y.commentNo, y.Contents

from (

           select articleNo, commentNo, rank() over (partition by ArticleNo order by commentNo desc ) RankNo

           from Article_comment with (nolock)

           where ArticleNo in ( 1, 2, 4, 6, 9) ) x

       join Article_comment y with (nolock) on x.ArticleNo = y.ArticleNo and x.CommentNo = y.CommentNo

where x.RankNo < 4

order by x.articleNo, x.RankNo




[테스트 결과]
APPLY 연산자를 사용하는 경우 각 게시물마다 최근 3개씩 NL Join으로 가지고 오기 때문에 이번의 경우에는 쿼리 비용이 가장 적음을 볼 수 있었습니다. 논리적인 읽기수를 보았을 때, CTE에 비해서는 약 17배 이상 비용이 절감되어짐을 볼 수 있습니다. APPLY 연산자를 사용한 방식의 경우 저장된 데이터량에 상관없이 늘 동일한 비용이 들어간다는 점도 다른 방식에 비해서 장점이였습니다.
이번 테스트르 하면서 느낀 점은 다양한 연산자나 구현 방식이 존재하지만 각 방식마다 장단점을 잘 이해하고, 해당 기능을 적절하게 사용하는 것이 중요하다는 것입니다. 좋은 기술도 사용 방식이나 경우에 따라서는 더 안좋은 결과를 보여줄 수 있습니다. (APPLY 연산자를 대할 때, DMV를 볼 때만 공식처럼 사용하고, 이해나 사용하려고 하지 않았던 점에 대해서 반성했습니다. ^^)

[참고문헌]
ms-help://MS.SQLCC.v10/MS.SQLSVR.v10.ko/s10de_1devconc/html/0208b259-7129-4d9f-9204-8445a8119116.htm

ms-help://MS.SQLCC.v10/MS.SQLSVR.v10.ko/s10de_6tsql/html/36b19e68-94f6-4539-aeb1-79f5312e4263.htm

http://weblogs.sqlteam.com/jeffs/archive/2007/10/18/sql-server-cross-apply.aspx

 

 


블로깅하다가 유용한 기능이 눈에 띄여서 공유합니다. 아래의 출처로 가면 좀 더 상세한 정보나 사례를 보실 수 있습니다.

보안 이슈나 운영 정책으로 인하여, 서비스 장비에 접근할 수 없고, 실 데이터 역시 제공 받지 못하는 경우가 있습니다. 이러한 경우 테이블에 데이터가 저장된 패턴을 모르기 때문에 어떤 실행계획을 풀리는지 검증하기가 쉽지 않습니다. 또, 이슈가 있는 경우 어떻게 실행계획이 풀리고, 어떻게 하면 해결되는지 테스트 해보기도 힘들구요. 이러한 경우 아래와 같이 데이터베이스 스크립트 생성을 할 때, 통계 및 히스토그램 데이터까지 받으면 좀 더 실서비스 환경에 유사한 환경에서 테스트를 해볼 수 있습니다.

장황하게 설명을 적었는데요, 내용은 아래와 같이 아주 간단합니다. ^^

1. "스크립트 생성 마법사 > 스크립트 옵션"을 선택하신 후, 개발 서버에 해당 스크립트도 적용해주시면 됩니다.
  - "통계 및 히스토그램 스크립팅" 옵션 선택




2. 통계 스크립팅을 추가하면 용량이 커진다고 경고가 뜹니다. 얼마나 커지길래 안내창이 뜨는지 확인해보았습니다. 
   AdventureWorks DB를 기준으로 하여 통계없는 경우, 통계만 추가, 통계 및 히스토그램 추가 3가지 경우로 스크립트를 생성해보았습니다.
   결과를 보시면 통계만 추가했을 경우는 용량과 스크립트가 동일했고, 히스토그램 추가 시 약 4.79배로 스크립트 용량이 증가합니다.
   (스크립트 용량이 커봐야 부담이 되어지지는 않을 듯 한데, 혹시 서비스에 영향을 줄 수 있지 않을까하는 생각은 들더군요. 서비스 장비에서 테스트는
    안해보았습니다. ^^)

사용중인 IP리스트를 DB를 사용하여 관리하고 싶을 때, 보통 2가지 방식으로 관리가 가능합니다.

 

1. 사용중인 IP를 개별적 저장하여 관리

2. 사용중인 IP영역을 선분으로 저장하여 관리

 

1. 컬럼 리스트 : (IP)

2. 데이터 예

(192.168.1.1)

(192.168.1.2)

(192.168.1.125)

(192.168.20.1)

1. 컬럼 리스트 (IPFrom, IPTo)

2. 데이터 예.

(192.168.1.1, 192.168.1.125)

(192.168.20.1, 192.168.20.1)

 

대상 IP를 바로 확인 가능하므로 직관적이다?

대상 IP가 많을 경우도 빠른 등록이 가능합니다.

 

IP 개수는 4,228,250,625개입니다. 대상 IP가 많아질수록 디스크 공간을 많이 차지하게 됩니다.

더욱이, 대량 IP를 등록할 때 서버부하 상승 및 작업시간도 많이 소요됩니다.

조회 쿼리 작성시 주의를 요합니다.


이제 제목이 적혀있는데로, [2안] 방식에서 조회 쿼리 작성시 주의가 필요한 부분에 대한 테스트를 진행해보도록 하겠습니다.

--@@ 임시테이블생성(IP 리스트테이블)
create table IPList (
       IPFrom char(12) not null
,      IPTo   char(12) not null
)
create unique clustered index idx_IPList_IP_From on IPList (IPFrom, IPto)

Result>
명령이 완료되었습니다.

-- @@ 테스트 데이터 입력 (D class 1~125까지 영역을 가지는 데이터 20만건 생성)
set nocount on 

declare @i   int = 1

while (@i <= 200000)
begin
    
  insert into IPList (IPFrom, IPTo)
       select 
             right('00' + cast((@i/65025)%255  + 1 as varchar(3)),3)
       +      right('00' + cast((@i/255)%255 + 1 as varchar(3)),3)
       +      right('00' + cast(@i%255 + 1 as varchar(3)),3)
       +      '001' as IPFrom
       ,
             right('00' + cast((@i/65025)%255  + 1 as varchar(3)),3)
       +      right('00' + cast((@i/255)%255 + 1 as varchar(3)),3)
       +      right('00' + cast(@i%255 + 1 as varchar(3)),3)
       +      '125' as IPTo

       set @i = @i + 1
end

Result> 44
명령이 완료되었습니다.

-- 아래는 문제가 있는 쿼리인가?
select top 1 *
from dbo.IPList with ( nolock )
where '002255001124' between IPFrom and IPto

 
Result> 실행계획만 보면 seek 풀린다. 하지만!!! 논리적 읽기수가 엄청나다. 그저 IP 하나 확인했을 뿐인데.

 
테이블 'IPList'. 검색 1, 논리적 읽기 537, 물리적 읽기 0, 미리 읽기 0, LOB 논리적 읽기 0,


-- 쿼리를 조금만 바꾸면....

select top 1 *

from dbo.IPList with ( nolock )

where '002255001124' between IPFrom and IPto

order by IPFrom desc

 

Result> 이제 실행계획도 그렇고, 우리가 원하는데로 수행되어지는 것을 볼 수 있습니다.

 


테이블
'IPList'. 검색 1, 논리적 읽기 3, 물리적 읽기 0, 미리 읽기 0, LOB 논리적 읽기 0,


실행계획도 정상적인데, 왜 논리적 읽기 수가 100배이상 차이가 나는 걸까요? 원인은 아주 간단합니다.

인덱스가 (IPFrom) 으로 잡혀있는 경우 IPFrom값이 낮은 순으로 정렬되어져 있기 때문에, IPFrom <= '002255001124' 조건을 해당 데이터 위에 있는 값들이 모두 만족하기 때문입니다.
Order by IPFrom DESC를 주었을 경우 IPFrom 값 비교를 큰 값부터 찾기 때문에, 처음으로 조건을 만족하는 값이 실제 찾고자 하는 값을 됩니다.


다른 방법으로도 위와 같은 현상을 해결할 수 있습니다. 인덱스를 (IPTo, IPFrom)으로 만드는 것입니다. 역시 테스트 해보겠습니다.


--
인덱스추가하기
create unique index idx_IPList_IP_To on IPList (IPto, IPFrom)
 

select top 1 *

from dbo.IPList with ( nolock )

where '002255001001' between IPFrom and IPto
 

Result>


테이블
'IPList'. 검색 1, 논리적 읽기 3, 물리적 읽기 0, 미리 읽기 0, LOB 논리적 읽기 0



결론!!!!!!!
    1. 선분으로 데이터를 보관하는 경우 일반적인 equal 비교를 통하여 접근하는 방식에서 생각했던 것과 조금 다르게 동작할 수 있으니 주의가 필요합니다.
    2. 실행계획에 index seek가 보여도 성능상의 문제가 되어질 수 있습니다.