로젝트에서 성능을 향상시키기 위해 SQL 튜닝에 전념하는 사이트들이 많이 있을 것이다. SQL 튜닝을 통해 성능 향상을 기대할 수 있는 것은 사실이다. 예전에는 성능 저하가 발생하는 경우 SQL 튜닝 보다도 해당 시스템의 CPU, 디스크 등의 자원을 증설하는 부분에 초점을 맞추었다. 이와 같이 자원을 증설하는 것보다 SQL을 튜닝하여 성능을 최적화하고자 하는 것은 매우 고무적인 현상임에는 틀림 없다.
그 만큼 관리자들의 생각이 IT 선진화로 가는 것은 아닐까? 하지만, 아직도 SQL 튜닝의 성능을 배가시킬 수 있는 물리적 구성에는 많은 허점과 편견이 존재한다. 이번 호에는 SQL 튜닝의 효과를 배가 시킬 수 있는 그 물리적 구성에 대해 자세히 확인해 보자.




성능을 향상시키는 물리적 구성을 이해해라


물리적 구성이 최적화되어 있지 않은 상태에서 SQL 튜닝으로 10배의 성능이 향상된다고 가정하자. 이런 경우 물리적 구성을 최적화한 후 SQL을 튜닝한다면 15배 이상의 성능 향상을 기대할 수 있을 것이다. 반드시 15배의 성능 향상은 아니지만 물리적 구성의 최적화 만으로도 우리는 성능 향상을 기대할 수 있게 된다.
필자가 어느 사이트를 지원했을 때의 일이다. 해당 사이트에서는 SQL 튜닝보다는 물리적 구성의 최적화에 초점을 두었었다. 디스크 I/O 분산과 파티션 테이블만을 이용하여 SQL 튜닝을 수행하지 않고 4배의 성능 향상을 확인했었다. 이 얼마나 놀라운 사실인가? 여기에 SQL 튜닝까지 수행한다면 10배의 성능이 향상될 SQL의 성능은 그 이상의 성능 향상을 기대할 수 있을 것이다. 이는 절대 놀라운 사실이 아니다. 이와 같은 이유에서라도 우리는 SQL 튜닝과 물리적 구성의 최적화를 병행해야만 할 것이다.
이제는 물리적 구성의 최적화를 간과해서는 안될 것이다. 한번 구성된 후에는 변경되기 힘든 것이 물리적 구성이다. SQL은 하나하나 최적화를 수행하여 적용하면 될 것이다. 하지만 물리적 구성은 한번 구성된 후 변경하기 위해서는 많은 어려움을 경험해야 할 것이다. 이와 같은 물리적 구성을 이제는 소홀히 여기지 말고 프로젝트 초기부터 성능과 연관 지어 수많은 고려를 해야 할 것이다.
성능을 고려할 경우에도 최적의 물리적 구성에 대한 정답은 없다. 하지만, 성능을 고려하여 물리적 구성에 대해 많은 고민을 한다면 우리는 성능을 보장할 수 있는 최적의 물리적 구성을 구현할 수 있을 것이다. 결국, 항상 생각하고 고민하는 습관이야 말로 해당 시스템을 최적의 시스템으로 구현할 수 있는 최선의 방법인 셈이다.
물리적 구성의 최적화는 여러 가지 요소에 의해 구성될 것이다. 그렇다면 어떠한 물리적 구성에 의해 성능은 향상되거나 저하될 수 있는 것일까? 아래와 같은 물리적 구성에 의해 우리는 성능 향상을 기대할 수 있을 것이다.


·데이터 저장 아키텍쳐 - 클러스터 팩터(CLUSTER FACTOR) 아키텍쳐
·테이블 아키텍쳐 - 파티션 테이블, IOT 테이블
·인덱스 아키텍쳐 - 결합 인덱스, 단일 컬럼 인덱스
·엑세스 아키텍쳐 - 병렬 프로세싱(PARALLEL PROCESSING) 아키텍쳐

위와 같은 물리적 구성 요소를 통해 우리는 성능을 향상시킬 수 있을 것이다. 새로운 시스템을 구축할 경우 위의 항목들을 항상 고려해야만 할까? 위의 항목들은 시스템이 서비스를 개시한 후에는 적용하기 힘들다. 그 이유는 물리적인 구성 요소이기 때문이다. 이제부터 각각의 항목에 대해 프로젝트 중에 어떻게 적용해야 그 성능을 최적화할 수 있는지 확인해 보자.




데이터 저장 아키텍쳐를 고려하자



여기서 언급하는 데이터 저장 아키텍쳐는 클러스터 팩터를 의미한다. 그렇다면 클러스터 팩터는 무엇을 의미하는가? 클러스터 팩터를 이해하기 위해서는 테이블에서 원하는 데이터를 액세스하는 유형과 저장되는 데이터에 대한 분석이 필요하다.
예를 들어 보자. 어느 카드사에 거래내역 테이블이 존재한다고 가정하자. 해당 카드사의 카드에 대한 거래가 발생하면 해당 테이블에 거래내역 데이터가 저장된다고 가정하자. 그렇다면 해당 테이블에는 어떻게 데이터가 저장되겠는가? 삭제되는 데이터가 없다면 테이블의 데이터는 INSERT되는 순서대로 데이터가 저장될 것이다. 그렇다면 거래일자에 의해 데이터가 발생하고 저장되므로 해당 테이블에는 거래일자 순으로 데이터가 저장될 것이다. 이는 무엇을 의미하게 되는가?
거래내역 테이블의 데이터를 저장하는 블록을 확인해보면 하나의 블록에는 동일한 거래일자가 저장된다. 데이터를 저장하는 하나의 블록을 확인해 보면 해당 블록에 거래일자 기준으로 2008년 4월 30일인 데이터가 저장되어 있다면 해당 블록에는 거의 대부분의 데이터가 2008년 4월 30일 데이터가 저장되어 있을 것이다. 물론 해당 블록이 2008년 4월 30일 데이터를 저장하는 처음 블록이라면 2008년 4월 29일 데이터가 같이 저장되어 있을 수도 있다.
여기서 중요한 것은 각각의 블록들은 대부분 동일한 거래일자 값을 가지는 데이터를 저장한다는 것이다. 이는 무엇을 의미하는가? 하나의 블록에는 10건의 데이터가 저장된다고 가정하자. 그리고 하루 데이터는 1000건의 데이터가 발생한다고 가정하자. 그렇다면 해당 1000건의 데이터는 몇 개의 블록에 저장되어 있겠는가? 1000건의 데이터는 100개의 블록에 10건씩 저장될 것이다.
이와 같기 때문에 해당 일자의 데이터를 모두 조회한다면 우리는 100개의 블록만 액세스하여 모든 데이터를 추출할 수 있게 된다. 그렇다면 우리는 불필요하게 액세스한 블록은 존재하지 않게 되며 또한 하나의 블록에서 대부분의 데이터를 결과로 추출하게 되므로 매우 효율적이라고 할 수 있을 것이다. 이와 같은 이유에서 거래내역 테이블은 거래일자 값에 의해 클러스터 팩터가 양호하다고 하게 된다.
결국 클러스터 팩터가 양호하다는 뜻은 각각의 블록은 클러스터 팩터가 양호한 컬럼의 값이 동일한 데이터로 저장되어 있어 우리가 액세스하고자 하는 데이터가 모여 있는 것을 의미하게 된다.
그렇다면 거래내역 테이블에서 거래일자 컬럼이 아닌 다른 컬럼에 대해 확인해 보자. 카드 회사의 가장 기본이 되는 카드번호 컬럼은 어떻게 되는가? 거래내역 테이블은 저장되는 순서에 의해 데이터가 저장될 것이다. 그리고 거래내역 테이블에서 많은 경우에 카드번호 컬럼의 값으로 데이터를 조회하게 된다. 그렇다면 ‘111’번 카드번호에 대해 거래내역 데이터를 조회한다고 가정하자. 해당 카드번호에 의해 생성된 거래내역 데이터는 100건이라고 가정하자.
그렇다면 해당 데이터를 액세스하기 위해 얼마나 많은 블록을 액세스해야 할 것인가? 거래일자 컬럼의 경우에는 각각의 블록에 동일한 거래일자 컬럼의 값을 가지는 데이터가 저장될 확률이 매우 높았다. 그 이유는 거래일자 값에 의해 순차적으로 데이터가 저장되기 때문이다. 그렇다면 카드번호 컬럼은 어떠한가? 해당 고객이 하루에 2번씩 사용하여 100번을 사용했다 하여도 각 데이터는 동일한 블록에 저장될 확률은 매우 낮게 된다. 이는 카드를 2번 연속해서 사용했다고 동일 블록에 저장되기 힘들 것이다.
그 이유는 전국에서 많은 사람들이 동시에 카드를 이용하게 되며 그렇기 때문에 해당 데이터들은 카드번호 값이 동일한 데이터들이 동일한 블록에 저장되기 매우 힘들게 된다. 이와 같은 상황에서 해당 카드번호 컬럼에 대해 조회를 수행해야 한다면 테이블에서 거의 100개의 블록을 액세스하게 된다.
결국 각 블록에 결과로 추출하고자 하는 데이터는 한건 씩 저장되어 있기 때문에 거래내역 테이블에 대해 카드번호 컬럼에 대해서는 클러스터 팩터가 불량하다고 이야기 하게 된다.
우리가 조회하는 데이터의 클러스터 팩터가 매우 양호하다면 각각의 블록에는 해당 컬럼의 값이 동일한 데이터들이 저장되므로 적은 블록을 액세스할 수 있게 되어 성능은 향상될 것이다. 우리가 조회하는 데이터의 클러스터 팩터가 불량하다면 각각의 블록에는 해당 컬럼의 값이 동일한 데이터들이 함께 저장되지 않게 되므로 많은 블록을 액세스해야 한다.
따라서 디스크 I/O의 증가로 성능은 저하될 것이다. 결국, 우리가 추출하고자 하는 데이터의 클러스터 팩터는 성능에 있어 매우 중요한 역할을 수행하게 된다.




클러스터 팩터의 정의를 이해하자


앞서 클러스터 팩터에 대한 예제를 통해 개념을 확인해 보았다. 클러스터 팩터는 우리가 추출하고자 하는 데이터가 얼마나 동일한 블록에 저장되어 있는가를 의미하게 된다. 그렇다면 클러스터 팩터는 어떤 기준으로 구분되는가? 아래 그림을 확인해 보자

사용자 삽입 이미지


클러스터 팩터 값은 위와 같이 정의할 수 있을 것이다. 인덱스를 통해 추출된 데이터가 100건이라고 가정하자. 인덱스를 액세스한 후에는 테이블을 액세스하게 되는 것은 당연한 사실일 것이다. 이 경우 인덱스에서 추출된 데이터는 100건의 데이터인데 테이블을 액세스하는 블록의 개수가 100이라면 위의 공식에 대입해보면 1이라는 값이 추출된다.
이와 같다면 우리가 원하는 데이터는 각 블록에 1건의 데이터만이 존재한다는 의미가 된다. 그러므로 해당 액세스는 클러스터 팩터가 불량하게 된다. 이와 같다면 우리도 모르게 성능 저하가 발생할 수 있게 된다. 반대로 인덱스에서 100건의 데이터가 추출되었지만 테이블 블록은 2개만 액세스했다면 위의 공식에 적용하면 값은 100/2이므로 50의 값이 추출되어 양호한 클러스터 팩터가 될 것이다. 클러스터 팩터가 양호하면 액세스하는 블록의 개수는 감소하게 되므로 자연스럽게 성능은 향상 될 것이다.
위의 클러스터 팩터 값의 정의에서 우리는 무엇을 이해해야 하는 것일까? 공식을 외운다고 우리가 클러스터 팩터에 대해 모든 것을 해결할 수 있는 것은 아니다. 우리에게 지금 필요한 것은 우리가 엑세스하는 데이터에 대해 클러스터 팩터를 최적화한다면 성능을 향상시킬 수 있다는 것이다. 이제부터 클러스터 팩터의 속성을 파악하고 우리가 엑세스하고자 하는 데이터에 대해 클러스터 팩터를 최적화하는 방법을 확인해 보자.




클러스터 팩터의 속성을 파악해라


클러스터 팩터에는 우리가 아직까지 언급하지 않은 하나의 속성이 존재한다. 그렇다면 클러스터 팩터의 속성은 무엇인가? 하나의 테이블에서는 하나의 컬럼에 의해서는 클러스터 팩터를 최적화할 수 있다는 것이다. 이는 우리에게 클러스터 팩터를 최적화하는 방법에 많은 고려 사항과 제한 사항을 발생시키게 된다.
그렇다면 정말로 하나의 테이블은 하나의 컬럼으로만 클러스터 팩터를 양호하게 할 수 있는 것인가? 앞서 언급한 거래내역 테이블을 다시 한번 확인해 보자. 거래내역 테이블은 거래일자 순으로 데이터가 저장되기 때문에 각각의 블록은 동일한 거래일자 데이터가 저장될 것이다. 그렇기 때문에 이 상태 그대로라면 해당 테이블은 거래일자 컬럼에 의해 클러스터 팩터가 최적화된다.
거래내역 테이블은 거래일자 컬럼의 값으로도 조회를 하지만 카드번호 컬럼의 값으로 많은 조회가 발생한다고 가정하자. 그렇다면 거래일자로 조회하는 액세스는 클러스터 팩터가 양호하기 때문에 자동으로 성능이 향상될 수 있지만 카드번호 컬럼으로 조회하는 액세스는 클러스터 팩터가 양호하지 않기 때문에 해당 액세스에 대해서는 성능이 저하될 것이다. 이와 같은 경우 우리는 카드번호 컬럼으로 클러스터 팩터 최적화를 수행해야 할 것이다.
거래내역 테이블에 대해 카드번호 컬럼으로 클러스터 최적화를 수행한다면 해당 거래내역 테이블에는 어떤 현상이 발생하게 되는가? 카드번호 컬럼으로 클러스터 팩터를 최적화하므로 거래내역 테이블은 각각의 블록에 카드번호 컬럼의 값이 동일한 데이터들이 저장될 것이다.
이와 같이 데이터가 저장되어야만 우리는 거래내역 테이블이 카드번호 컬럼에 의해 클러스터 팩터가 양호하다고 이야기할 수 있을 것이다. 이처럼 구성하는 방법을 클러스터 팩터 최적화라고 한다. 카드번호 컬럼으로 클러스터 팩터 최적화를 수행하면 어떤 현상이 발생하게 되는가?


·카드번호 컬럼 - 각각의 블록에 동일한 카드번호 컬럼의 값이 저장
·거래일자 컬럼 - 각각의 블록에 서로 다른 거래일자 컬럼의 값이 저장

위와 같은 현상이 발생하게 된다. 이 뜻은 거래일자 컬럼의 값에 대해서 기존에는 클러스터 팩터의 값이 양호했지만 카드번호 컬럼으로 클러스터 팩터 값을 최적화한다면 더 이상 거래일자 컬럼의 값으로는 클러스터 팩터가 최적화되지 않는다는 의미가 된다.
\2008년 4월 30일 사용한 거래내역 데이터를 확인해 보자. 2008년 4월 30일에 사용한 거래내역 데이터는 연속된 블록에 저장될 것이다. 따라서, 해당 블록들을 확인해 본다면 동일한 2008년 4월 30일 데이터들이 저장될 것이다. 이러한 이유에서 거래일자 컬럼에 의해 클러스터 팩터가 최적화되었었다.
하지만 해당 데이터의 카드번호 값은 어떠한가? 하루에 동일한 카드가 몇 번이나 사용되겠는가? 업무적으로 차이가 발생할 수 있지만 하나의 카드가 동일한 일자에 수 십번 아니 수 백번 사용되지는 않을 것이다. 그렇다는 이야기는 무엇인가? 각각의 블록에 동일한 카드번호 컬럼의 값을 가지는 데이터를 저장하는 순간 각각의 블록에는 동일한 거래일자 값의 데이터는 블록에 저장되지 못한다는 것이다. 그러므로 카드번호 컬럼으로 클러스터 팩터를 최적화한다면 그 동안 클러스터 팩터가 양호했던 거래일자 컬럼의 클러스터 팩터는 불량해 진다.
결국 하나의 컬럼으로 클러스터 팩터를 최적화 한다면 다른 컬럼들은 일반적으로 클러스터 팩터가 불량하게 된다. 이는 무엇을 의미하는 것일까? 카드번호 컬럼으로 클러스터 팩터를 최적화한다면 카드번호 컬럼의 값으로 조회하는 액세스의 성능을 최적화할 수 있지만 그에 반해 거래일자 컬럼으로 데이터를 액세스하는 경우에는 클러스터 팩터가 불량해 지므로 성능은 저하된다.
이처럼 클러스터 팩터의 최적화에는 장점과 단점이 존재하게 된다. 어떤 컬럼으로 클러스터 팩터를 최적화한다면 다른 컬럼들의 클러스터 팩터는 불량해 지게 된다. 어떤 카드회사에서 필자가 실제로 거래내역 테이블에 대해 카드번호 컬럼으로 클러스터 팩터를 최적화해 보았었을 때의 일이다. 카드번호 컬럼으로 데이터를 액세스하는 어플리케이션은 전체적으로 성능이 안정화되었다.
하지만 거래일자 컬럼으로 매일 작업을 수행하는 어플리케이션은 기존 성능에 비해 10배 정도의 성능 저하가 발생했었다. 그래서 개발자로부터 연락이 왔으며 필자는 내일이 되면 거래일자 컬럼으로 클러스터 팩터가 최적화되니 원래의 성능을 보장할 수 있을 것이라고 언급했다. 다음 날이 되자 필자가 말한 것이 현실로 나타났다. 기존 거래일자 컬럼으로 데이터를 액세스하는 애플리케이션은 기존 성능을 보장 받게 되었다.
이는 무엇을 의미하는가? 테이블의 클러스터 팩터는 해당 테이블을 액세스하는 어플리케이션에 엄청난 영향을 미친다는 것이다. 이와 같이 성능에 있어 큰 영향을 미치는 클러스터 팩터를 더 이상 간과해서는 안될 것이다. 프로젝트 중에 중요 테이블에 대해 클러스터 팩터를 고려했는지 안 했는지는 해당 시스템의 전체 성능에 있어 매우 중요한 역할을 수행하게 된다.
아직도 많은 사람들은 클러스터 팩터에 대한 중요성을 인식하지 못하고 있는 것이 현실이다. 관리자부터 클러스터 팩터에 대한 중요성을 인식해야지만 많은 시스템에 필요한 클러스터 팩터를 최적화할 수 있을 것이다. 데이터베이스의 데이터가 대용량으로 변하면서 또한 많은 애플리케이션이 수행되는 시스템에서는 클러스터 팩터가 성능에 있어서는 매우 중요한 역할을 수행하게 된다. 이제는 더 이상 클러스터 팩터를 간과해서는 안될 것이다. 우리가 많이 액세스하는 컬럼으로 클러스터 팩터를 최적화하는 순간 우리는 최적의 성능을 기대할 수 있을 것이다.
클러스터 팩터를 최적화하는 방법에는 많은 방법이 존재한다. 테이블 재구성 방법부터 파티션 테이블을 이용하는 방법까지 여러 방법이 존재하며 이에 대한 방법은 다음 호에 자세히 언급하도록 하겠다. 우리가 생각하지 못한 클러스터 팩터에 대한 생각의 전환이야 말로 대용량 데이터베이스에 대해 성능을 최적화할 수 있는 핵심 요소이다.



제공 : DB포탈사이트 DBguide.net

Posted by 서오석
,