본문 바로가기

전문가를 위한 오라클 데이터베이스 아키텍처

[DB Study Season2] 01.성공적인 오라클 어플리케이션 개발

필자는 지 금껏 오라클 데이터베이스와 그것을 사용하는 개발지들과 긴 시간을 함께 했다. 최큰 18 년 동
안 수행한 여러 프로젝트 중 일부는 성공적이었고 일부는 완전히 실패한 것들이었는데, 거기 서 얻은 귀
중한 경험들을 몇 마디 로 요약하면 다음과 같다.
• 데이터베이스를 기반으로 (데 이터 베이 스에 의존적으로) 만들어진 애플리케이션은 데이터베이 스를 어
떻게 사용하느냐에 따라 성공할 수도 실패할 수도 있다. 모든 애플리케이션이 데이터베이 스를 기
반으로 구현되기 때문에 당연한 결론이긴 하겠지만, 펼지는 유용한 애플리케 이션이라면 당연히 데
이터를 어디엔가 영구적으로 저장해야 한다고 생각한다
• 애플리케 이션은 계속 변화하지만 데 이 터는 영원하다. 애플리케이션을 구축하는 것만이 중요한 것
이 아니라, 애플리케이션 안에 보이지 않게 존재하는 데이터가 더 중요하다.
• 개발팀에게 가장 필요한 것은 데이터베이 스의 핵심을 잘 알고 있는 개발자로서, 데이터베이스의 로
직을 잘 구축하고 시스탱이 처음부터 잘 구동되도록 구축할 책임이 있는 사람들이다 개발을 완료
한 후에 튜닝을 다시 한다는 것은 시스템을 제대로 된 방법대로 구축하지 않았다는 것을 의미한다.
위에 적은 이야기들이 너무도 당연한 것처럼 보이겠지만, 필자의 경험 에 비추어 볼 때 무수히 많은 사
람들이 데이터베이스를 마치 블랙박스(무엇인지 알 필요가 없는 것)보듯 접근한다는 것이다. 수많은 개발
자들이 SQL을 배우는 고행과 같은 일에서 그들을 구원해줄 ‘SQL 생성기’ 를 갖고 있는 듯하다. 그리고
SQL 생성기를 단지 다른 평범한 파일처럼 손쉽게 사용하고 키보드로 친 것을 읽는 것처럼 쉽게 시용
할 수 있을 거라 생각한다. 물론 어떻게 생각하든 자유지만 이런 식의 생각은 완전히 착각이다. 쉽게
말해서 데이터베이 스를정확하게 이해하지 않고제대로된애플리케이션을잘작성할수없다 이번장
에서는 여러분이 왜 데이터베이 스에 대해 알아야 하며 특히 왜 데이터베이 스를 이해해야 하는지 다음
과 같은 주제를 가지고 알아볼 것이다.
• 데이터베이스 아카텍처는 어떻게 작동하며, 어떤 모양인가?
• 동시성 제어란 무엇이며, 그것이 여러분에게 의미하는 것은 무엇인가?
• 애플리케이션을 처음부터 어떻게 튜닝할 것인가?

• 데이터베이스의 기능들이 어떻게 구현되어 있는가? 데이터베이스의 기능들은 여러분이 생각하는
것과는 다른 방법으로 구현되어 있을 수도 있다.
• 여러분이 사용하고 있는 데이터베이스가 이미 제공하고 있는 기능들은 무엇이며, 일반적으로 그
기능들이 여러분이 직접 만든 것들보다 더 뛰어난 이유는 무엇인가?
• 기본 이상으로 SQL을 잘 알아야 하는 。l유는 무엇인가?
.DBA와개발자들은서로이기려고경쟁하는적이 아니라한팀이다
이 내용들을 보고 여러분은 시작도 하기 전에 배워야 할 것들이 너무 많다고 느낄지 모르겠지만, 잠시
다음 이야기 를 생각해보면 이해가 쉬울 것이다. 여러분이 처음 접하는 대형 ‘운영체제 (05)’ 에서 높은
확장성을 가진 전사적 애플리케이션을 개발할 경우에 해야 할 첫 번째 일이 무엇이라 생각하는가? “새
로운 운영체 제가 어떤 원리로 작동하는지 프로그램들이 그 위에서 어 떻게 수행되는지 등을 공부해야
한다”고 대답할 것이 다. 여러분의 대답이 이와 다르다면 성공적인 애플리케 이 션 개발에 실패할 가능
성이 매우높다.
윈도우즈 (Windows)와 리녹스 (Linux) 운영체제를 생각해보자 여러분이 숙련된 윈도우즈 프로그래머
인데 리녹스 플랫폼에서 새로운 애플리케이션의 개발요청을 받았다고 한다면, 아마도 두 가지를 새로
배워야 할 것이다. 첫 번째는 메모리 관리를 다른 방법으로 수행한다는 것이며, 다른 하나는 서버 프로
세스 구축 방법이 상당히 다르다는 것이다. 윈도우즈 환경에서는 자체적으로 실행이 기능한 다수의 쓰
레드를 갖는 한 개의 프로세스를 개발해야 한다. 그러나 리녹스 환경에서는 한 개의 독립적으로 실행
가능한 프로세스를 개 발하지는 않을 것이다 여러분은 동시 에 작업을 처리 하는 많은 프로세스를 개발
할 것이다 윈도우즈나 리녹스나 운영체제인 것은 사실이다. 이 운영 체제들은 둘 다 개 발자들에게 파일
관리, 메모리 관리, 프로세스관리, 보안등 많은동일한형 태 의 서비스를 제공한다. 그러나 이 둘은 매
우 다른 아카텍처를 갖고 있어서, 윈도우즈 환경에서 배운 많은 것들을 그대 로 리녹스 환경에 적용할
수가 없을 것이다(반대의 경우도 마찬가지다). 개발을 성공적으로 하려면 기존에 배운 것을 과감하게 버
려야한다. 이것은데이터베이스환경에 있어서도똑같이 적용되는원리다
운영체제를 잘 이해해야 애플리 케이션을 잘 만들 수 있는 것과 마찬가지로 데이터베이 스를 잘 이해해
야 애플리케이션을 잘 만들 수 있다. 데이터베이 스에 대한 이해는 성공적인 개발에 있어서 중요한 일이
다. 여러분이 사용하고 있는 데이터베이 스가 무슨 일을 하는지, 어떻게 그것을 수행하는지 이해하지 못
한다면, 여러분이 만들 애플라케이션은 실패한 프로그램이 될 것 이다. 또한 여러분이 SQL 서버에서 잘
작동하는 애플리케 이션이 오라클에서도 똑같이 잘 작동할 것이라 가정한다면, 애플라케이션은 또 다시
실패할 것 이다. 반대의 경우에도 마찬가지다. 잘 개발된 확장성 좋은 오라클 관련 애플리케 이 션이라도
중요한아키 텍트의 변 경 없이는 SQL 서버에서 수행하지 않을것이다. 윈도우즈와리녹스가둘다운영
체제이긴 하지만 근본이 다른 것처럼, 오라클과 SQL 서버(다른 많은 데이터베이스도 포함해서 )는 둘 다

데이터베이스지만 근본적으로 다르게 작동한다
필자의 접근법
본론으로 들어가기 전에, 애플리케이션 개발에 대한 필자의 접근법을 이해할 필요가 있다. 필자는 여러
문제에 직연할 때 문제를 해결하기 위해 주로 데이터베이 스 중심 접근법을 사용한다 펼자는 문제 해 결
을 데이터베이스 안에서 수행할 수만 있다면 그렇게 할 것이다 여기에는 두 가지 이유가 있는데, 첫 번
째는 내 가 데이터베이스의 기능을 구축한다면 그것을 어디서든 전개할 수 있다는 것이다. 윈도우즈에
서부터 여러 가지 유닉스와리녹스시스탱뿐아니라 AIX 그리고유명하고상업적으로이용할수있는
서버 운영체제 중 오라클을 설치하여 사용할 수 없는 시 스템은 없다고 알고 있다. 모든 운영체제에 설
치된 오라클에서는 통일한 오라클 소프트웨어와 옵션을 선택하여 사용할 수 있다. 필자는 종종 나의 노
트북 컴퓨터로 가상 머신으로 리녹스 또는 윈도우즈 운영체제에서 오라클 l1g 또는 10g를 실행시켜 다
양한 솔루션들을 구축하거나 테스트하곤 한다 동일한 데이터베이 스를 사용하지만, 서로 다른 운영체
제에서 돌고 있는 다양한 서버에 전개해서 사용할 수 있다. 데이터베이스 외부에서 특정 기능들을 구현
해야 할 경우, 원하는 기 능들을 개발하거나 시용하기가 무척 어렵다는 것을 알게 된다. 자바가 많은 사
람들에게 매력을 주는 특징 중 하나는 자바 기반으로 만든 프로그램은 항상 같은 가상 환경, 즉 자바 가
상 머신(JVM)에서 컴파일되며, 시스템 간에 높은 이식성을 갖는다는 것인데 필자에게는 데이터베이스
도정확히자바와동일한가상머신이며 가상운영체제인것이다.
그러므로 필지는 데이터베이 스에서 할 수 있는 모든 것을 해보려고 한다. 만일 펼자의 요구사항이 데이
터베이스 환경으로 처리할 범위를 벗어난다면, 데이터베이 스가 아닌 자바에서 처리한다. 이런 이유에
서 모든 운영 체제의 복잡한 내부구조까지는 알 필요가 없어진다 물론 필자는 여전히 가상 머신들(오라
클 또는 때때 로 πM) 의 작동법을 이해해야만 한다. 여러분은 사용하고 있는 툴들에 대해 알 필요가 있
다 여러분이 열심히 툴들에 대한 지식을 차곡치곡 습득한다면 그 툴들은 (여러분이 그 툴을 잘 이해해준
것에 대한 보답으로) 주어진 운영체제 상에서 여러분을 위해 최선을 다해 일할 것이다
따라서 여러분이 하나의 ‘가상운영체제’의 복잡한 내용들을 이해한다면, 여러 다른 운영체제 에서 정
상적으로 작동하는 확장성이 좋은 애플라케이션을 충분히 구축할 수 있을 것 이다. 물론 운영체제에 대
해 몰라도 된다는 말이 아니다. 데이터베이스 애플리케이션을 구축하는 소프트웨어 개발자로서 운영체
제를 완전히 이해하진 않아도 괜찮다는 말이며 , 운영체제들 간에 가지고 있는 미묘한 차이를 다룰 필요
가 없다는말이다. 오라클소프트웨어를운영하는 DBA들은 운영체제와관련된 튜닝 기법을 많이 알고
있을 것이디 (DBA가 그것도못한다면, 제빌 새로운 DBA를뽑도록하라!) 만일 여러분이 클라이언트 서버
소프트웨어를 개발하고 있는데, 많은 양의 코드가 데이터베이 스와 가상 머신(아마도 자바 가상 머신이 가
장 인기 있는 가상 머신일 것이다) 외에서 개발되어 있다면 여러분은 운영체제에 대해 다시 한 번 관심을

가져야만할것이다.
필자는 데이터베이스 소프트웨어 개발에 관해서 분명한 원칙을 수년 동안 고수하고 있다.
• 가능하다면 하나의 SQL 문으로 프로그램을 개발해야 한다. 믿지 못하는 분들이 있을지 모르겠지
만, 이것은거의항상기능하다.
• 하나의 SQL 문으로 할 수 없다면 PL! SQL로 구현하도록 하랴. 물론 PL! SQL은 가능한 최소한
으로사용하는것이좋다 ‘많은코드 = 많은벼 그 적은코드= 적은버그’라는 말을기 억하라.
• 그것을 PL! SQL로도 할 수 없다면 자바 내장 프로시저 (Java stored procedure)를 사용하도록 하자.
최근 오리클 9i 버 전 이상에서는 그렇게까지 할 필요도 거의 없어졌다.
• 자바로도 프로그램을 개발할 수 없다면 C 의 외부 프로시저를 시용하여 프로그램을 개발해보자. 이
런 프로그래밍 방식은 빠른 실행성능을 필요로 하거나 C로 작성된 외부 프로그램의 API를 시용할
필요가 있을 때 자주 사용된다.
• 만일 프로그램을 C 외부 로직으로도 구현할 수 없다면, 그 일을 왜 해야만 하는지 심각하게 고민할
필요가있다.
이 책 전반에 걸쳐 위에서 이야기한 개 발 철학을 어떻게 구체적으로 구현하는지 알아볼 예정이다, SQL
만으로 일을 할 수 없거나 효율성이 떨어지는 경우에는 PL! SQL을 시용할 것이다, PL! SQL은 오랫동
안 사랑받아온 프로그래밍 툴이다 2010 년 현재를 기 준으로 20년 이상 튜닝한 내용이 PL!SQL 안에
녹아있다 사실, 오라클 10g에 서 PL!SQL 컴파일러는 처음으로 최적화하여 새롭게 만들어졌다. 아마
도 여러분은 SQL과 이 토록 강하게 결합되고 SQL 에 최적화되어 일을 수행할 수 있는 언어논 찾지 못
할 것이다, PL! SQL에 서 SQL을 너무도 자연스럽게 사용할 수 있다. 이에 비해 비주얼 베이직에서부
터 자바까지 다른 모든 언어들은 SQL을 억 지 로 끼워 맞춘 것처럼 사용해야 한다. 절대 자연스럽게 느
껴지 지 않는다 단지 그 언어 자체의 확장 기능 정도일 뿐이다. 혹시 PL ! SQL만으로는 부족하여 일을
할 수 없는 경우에는 ( 최신 데이터베이스 버전에서는 거의 있을 수 없는 일) 자바를 사용할 것이다. 때로 일
반적으로 C만을 선택해야 하는 때거나 빠른 속도가 필요한 경우에는 C로도 만들 것이다. 종종 빠른 개
발 속도가 선택의 이유가 된다면 자바의 NATIVE Compile(자바 bytecode를 특정 운영체제에 최적화된
객처1 묘드로 전환하는 기법)을 시용하여 구현할 수도 있다. 많은 경우에 이렇게 하면 자바를 C만큼 빠르
게실행시킬수있다.
딛래바A
를극 ...,...,- 처그버
t::::IL... t::::I
필자는 몸소 체 험한 다oð한 실패 사례들을 통해 데이터베이스를 기반으로 만든 다수의 소프트웨어 개
발사업이 왜 그토록 자주 실패를 겪는가에 대한 해답을 갖고 있다. 한 가지 짚고 넘어갈 것은 문서로는
4
I
• • • CHAPTER 01 성공적인 오라클 애를리케이션 개발
실패로 기록되지 않았지만 개발한 것을 크게 수정하고, 아카텍처를 재설계하고, 튜닝을 해야 할 필요성
때문에 원래 계획된 일정보다 출시나 적용이 많이 연기된 프로젝트들도 실패 사례에 포함했다는 점이
다. 개인적으로는 지연된 프로젝트도 실패라 생각한다. 대다수 프로젝트가 일정에 맞추어 끝낼 수 있었
거나 심지어 더 빨리 끝낼 수 있는 것들이었기 때문이다
프로젝트가 실패하는 가장 일반적인 이유 중 하나는 데이터베이스에 대한 실질적인 이해 부족으로, 사
용하고 있는 기본 툴에 대한 기초지식이 부족했기 때문이다. 블랙박스 접근법은 개발자들을 데이터베
이스로부터 보호하려고 의도적으로 결정한 방법이다. 그들은 실제로 데이터베이스에 대해 어떤 것도
배우지 않도록 종용받는다. 많은 경우에 그들은 데이터베이스를 다루는 것조차도 금지된다. 이러한 접
큰법이 생겨난 이유는 막연한 두려움과 관련이 있다. 개발자들은 데이터베이스는 ‘어렵고’ , SQL, 트랜
잭션, 그리고 데이터 무결성도 ‘어렵다’ 라는 말을 계속 들어왔다 즉, 기본 개념에 대한 막연한 두려움
이 개발자들에게 존재한다. 이런 두려움을 회피하기 위해 아무도 이런 어려운 일을 하지 않는 것이다.
그들은 데이터베이스를블랙박스처럼 다루고, 몇 가지 소프트웨어 툴로모든코드를생성하고 있다. 개
발자들은이런 ‘어려운’ 데이터베이스를다룰필요가없도록많은보호막으로그들자신을보호한다.
필자는 데이터베이스로 개발하는 것이 어렵다고 생각하는 것을 이해할 수 없다. 사실 필자에게는 자바
나 C를 배우는 것이 데이터베이스의 개념을 배우는 것보다 훨씬 더 어려웠다. 물론 지금은 자바와 C를
잘 다루지만, 이것들을 능숙하게 사용하기까지는 데이터베이스를 능숙하게 시용하는 것보다 훨씬 더
많은 노력이 필요했다. 데이터베이스가 어떤 방법으로 수행되는지 알 필요는 있지만, 데이터베이스 내
부와 외부에서 일어나는 모든 것을 알 필요는 없다. 그런데 C나 자바/J2EE로 프로그래밍을 할 경우에
는 언어 안팎의 모든 기능들을 알아야 한다. 이 언어들은 엄청난 기능들을 가진 언어들이기도 하다.
만일 여러분이 데이터베이스 애플리케이션을 구축하고 있다면 가장 중요한 부분은 데이터베이스다.
성공적인 개발팀이라면 이 사실을 인정하고, 팀 구성원들에게 이 사실을 알랄 것이며, 데이터베이스에
집중하도록 할 것이다. 그러나 필자는 위의 사실과는 정반대의 프로젝트를 여러 번 수행하였다.
아주 일반적인 개발 시나리오는 다음과 같다.
• 개발자들은 GUI 툴이나 자바와 같이 화변단을 구축하는 데 시용하는 언어를 잘 다루었다. 많은 경
우에 그것들을 배우는 데 몇 주에서 몇 달의 시간을 보내기도 했다.
· 그개발팀원들은오라클사용경험이 전무했고 오라클교육조차받은적이 없었다. 대부분데이터
베이스에 대한 경험도 전혀 없었다 그들은 또한 데이터베이스 독립적’ 이 되라는 강요를 받는데,
여러 가지 이유들로 따르기를 바랄 수는 없는 것이다. 가장 명백한 사실은 그들은 데이터베이스가
어떤 것이지 충분히 알지 못하고, 데이터베이스들간에 가장기본적인공통분모(기능)를찾기 위해
무엇을 해야 하는지조차 알지 못한다는 것이다.
5
전문가를 위한 오라클 데이터베이스 아키텍처 .. . .
• 비록 눈부시도록 아름다운 화면을 개발하였으나 개발자들은 심각한 성능 문제, 데이터 무결성 문
제, 장애 문제 등에 직변했다.
필연적으로 나타날 수밖에 없는 성능 문제들이 발생하여 결국 필자에게 달려와 문제를 해결해달라는
요청을 한다(쑥스럽지만 과거엔 필자가 그러한 문제들의 원인이었다) . 물론 어떤 경우에는 필자도 사용해야
할 새로운 명령어의 문법을 정확히 기억하지 못하는 때도 있었다. 이런 경우는 SQL Reference 매뉴얼
을 개발자들에게 요청했는데 개발자들에게서 가지고 있던 가장 최신의 문서라며 오라클 60 의 문서를
넘겨받았다. 개발은 73 버전으로 진행하고 있었는데 매뉴얼은그보다 5년 전에 나온 60 벼전의 것을
사용했던 것이다. 이 매뉴얼이 그들이 갖고 일하는 전부였는데도 그들은 이것에 대해 별로 상관하지
않는 것처럼 보였다. 성능을 측정하기 위한 트레이스와 튜닝을 위해 알아야 할 도구들이 6.0에서는 존
재하지 않는다는 사실을 모르는 것처럼 보였다. 트리거 내장 프로시저들 그리고 수백 가지의 다른 기
능들이 그 문서가 작성된 뒤 5 년 동안에 추가되었다는 사실도 모르는 것처럼 보였다. 문제를 해결하는
것과는 또 다른 문제로 왜 그들이 도웅을 받을 수밖에 없었는지 알 만했다
I Note I 요즘도 데이터베이스 애플리케이선 개발자들이 개발을 위한 잠고문서를 아예 일지 않는다는 사실을 자주 발견한
다 필자가 운영하는 웰 사이트인 asktom .oracl e.com Ol I는 “문법이 어떻게 되나요?", “우리는 매뉴얼도 없습니다 제발 도
와주세요”라는 질문을 자주 받는다. 이런 종류의 질문에 일일이 답히는 대신에 누구나 사용 가능한 온라인 매뉴얼이 있다는
점을 알려준다 최근 15년 동안 “매뉴얼이 없어요” “자원에 접근할 수 없어요”라는 변명과 같은 질문들은 거의 사라졌다
otn.oracle.com(the Oracle Technology Network)과 groups.google.com (Internet discussion forums )과 같은 웹
사이트들이 많아져서 사람들이 문서가 없어서 찾을 수 없다는 변명은 할 수 없게 되었다‘ 요즘엔 모든 사람들이 모든 문서에
접근할 수 있으며 문서를 일거나 찾기만 하면 된다.
데이터베이스 기반 애플리 케이션을 구축하는 개발지들이 데이터베이스를 다루지 못한다는 사실이 내
게는 충격 이지만, 이런 태도 (역자 주- 개발자는 데이터베이스를 잘 다루지 못해도 된다는 태도)는 여전하다. 여
전히 많은 사람들은 개발자들이 데이터베이스를 공부하는 데 시간을 들이면 안 된다고 주장하고, 기본
적으로 데이터베이스에 대해 알아야 할 필요도 없다고 주장하고 있다. 왜 그럴까? 필자는 여러 번 다
음과 같은 말을 들은 적이 있다. “오라클은 세상에서 가장 확장성이 좋은 데이터베이스이기 때문에 배
울 필요가 없고, 그자 우리는 일만 하면 된다” 오라클이 세계에서 가장 확장성이 좋은 데이터베이스라
는 말은 맞다. 그러 나 오라클은 확장성이 뛰어나지만 확장성이 몹시 나쁜 프로그램도 쉽게 만들 수 있
다. 여러분은 오라클을 다른 여러 개의 소프트웨어로 대체할 수도 있고 소프트웨어들이 정상적으로 통
작하기도 한다. 사실 잘 동작하는 애플리케이션을 만드는 것보다 잘 동작하지 않는 애플리 케이션을 만
드는것이 더 쉽다. 여러분이 잘모르는사실이 있다면 세상에서 가장확장성 좋은 데이터베이스로단
한 명의 사용자만을 위한 시스템을 구축하기 쉽다는 것이다. 데이터베이스는 하나의 도구라고 할 수 있
는데, 어떤 도구든지 잘못 이용하면 재앙이 될 수도 있다. 여러분은 호두까기를 가지고 호두를 마치 망
치로 내리치 는 것처럼 부셔서 먹겠는기.? 물론 그렇게 할 수도 있지만 이것은 호두까기 기구의 올바른
6
• • • CHAPTER 01 성공적인 오라클 애플리케이선 개발
시용법이 될 수 없으며 , 결과적으로 가루가 된 호두를 먹게 되거나 자칫하면 손가락을 다칠 수도 있을
것이다(역자 주 툴의 용도를 정확하게 알고 있어야 툴의 기능을 극대화하여 사용할 수 있다는 뜻l. 여러분이 데
이터베이 스를 모른 채 개발을 계속하면 비슷한 일이 일어날 것이다.
언젠가 문제투성이 프로젝트에 투입 된 적이 있었다. 개발자들은 엄청나게 많은 성 능 이슈에 직면하고
있었다. 그들이 구축한 시스템은 많은 트랜잭션을 ‘직 렬화(serializing)’ 하고 있었다. 많은 사람들이 동
시에 일하는 것이 아니라 모든 사람들이 정말 길게 줄을 서서 모두가 서로 일들을 처리하기 위해 기다
리고 있는 것 처럼 보였다. 애플리 케이션 아키텍처를 보니 그들이 구축한 시 스템 아키텍처가 무엇인지
알 수 있었다. 고전적인 3-tier 접근법을 시용하고 있었다. 그것들은 웹 브라우저와 통신하는 JSP로 된
미 들 티어 애플리케이션 서 벼를 갖고 있었다.JSP는 웹 브라우저에서 메시지 를 받아 또 다른 계층의 프
로그램과 EJB (Enterprise Java Beans)를 통해 연결하였다.EJB는 모든 SQL을 수행하는 역할을 담당했
다. EJB 안에 들어 있는 SQL은 몇 개의 외부 툴로 생성되었고 데이터베이 스와는독립적인 형태로 개
발되어 있었다.
이 시스뱀에서 무언가를 진단한다는 것은 매우 어려 웠는데, 왜냐하면 프로그램 코드를 전혀 손대거나
추적할 수 없었기 때문이다. Instrumenting code (역자 주 버그 추적, 성능 모니터링, 레벨들을 측정하기 위
해 프로그램 안에 심어놓은 프로그램)는 이미 개발된 프로그램 코드를 디벼깅할 수 있게 하는 정교한 기술
이다. 이 프로그램들은성능이나용량또는로직의 문제들에 직면할 때 어디서 문제가발생했는지 정확
히 찾을 수 있도록 해준다. 브라우저와 데이터베이 스 사이 다시 말해서 전체 시스뱀에서 여러 가지 의
심이 되는 상황이나 문제가 어디서 발생하는지 찾을 수 있도록 도와주는 기능을 한다. 오리클 데이터베
이 스는 조금은 무겁게 Instrumenting code가 내부에 담겨 있는데 , 비록 여러분의 애플리케이션에
Instrumenting code를 넣어두지 않았다 하더라도 적당한 위치에 분석을 위한 장치를 두어 손쉽게 꼈
다켰다 할수 있다.
따라서 데이터베이 스 자체 에서 손쉽 게 얻을 수 있는 성능 진단 기 능과 같은 정밀하고 자세한 성능 진단
도구 없이 성능 이슈를 진단해야만 하는 상황에 직면했다. 다행히 도 이번 경우는 조금 쉽 게 해 결할 수
있었다. 오리클의 V$ 태이블(오라클의 Instrumentation code를 통해 데이터베이스 성능 통계를 V$ 테이블을
통해 참조할 수 있다)들을 아는 사람이 살펴보면, 데이터베이 스에 대한 주요한 모든 자료를 큐로 관리하
는 한 개의 테이블에서 찾을 수 있다. 애플리케이션들은 다른 프로세스가 이 테이블에서 자료를 뽑아
처리하는 동안 이 테이 블에 또 다른 자료를 기록한다 조금 더 자세히 살펴보면, 우리는 이 테이블의 컬
럼 에서 비 트랩 인텍 스를 찾아볼 수 있다(비 트맴 인 텍스에 대한 정보는 이 책 후반부에 다룬다) . 이 컬럼, 즉
프로세스 플래그 컬럼 이 단지 Y와 N 이라는 두 개의 값만 가질 것이라고 추론했다. 자료가 입력 될 때는
프로세스가진행 중이 아니라는 표시인 N값이 입력되며 다른 프로세스가읽고자료를 처리할때는프
로세스는 N값을 프로세스가 완료되었다는 것을 의미하는 Y값으로 변경한다는 것이다. 개발자들은 N
값에 해탕하는 것만 빨리 찾으면 되고 해당 컬 럼에 인텍스를 생성하면 된다는 것을 알고 있었다. 그들
7
전문가를 위한 오라클 데이터베이스 아키텍처 • ••
은 low-cardinality 컬럼으로 구성한 비트맴 인텍스에서 구별되는 값의 개수가 너무 작은 컬럼을 읽었
다. low-cardinality 컬럼은 구별되는 값이 적게 구성되어 있는 컬럼을 말한다. 그래서 자연스럽게 딱
맞는 것처 럼 보였다(비 트맴 인텍스에 대해 자세히 알고 싶다면 구글에서 찾아보라 low-cardinality 관련 정보
는넘치도록많다).
그러나 이 비트맴 인텍스가 모든 문제의 원인이었다. 비트뱀 인텍스에서는 한 개의 ‘키 (keyentry)’ 가
수백 개 이상의 많은 로우를 가리킨다. 만일 여러분이 비트뱀 인텍스 키를 엽데이트하면, 키가 가리키
고 있는 수백 개의 레 코드들이 동시에 ‘락 (Lock)’ 에 걸리게 된다. 따라서 누군가 비트랩 인텍스에서 N
으로 되어 있는 레코드에 대해 락을 건다면 비트랩 인텍스에 있는 수백 개의 다른 N 레코드에도 동시
에 락을 걸 게 될 것이다. 이 기간 동안 이 테이블을 읽고 그 레코드들을 처리하려는 프로세스는 N값을
가진 자료를 Y값으로 변경할 수 없게 될 것이다. 왜냐하면 이 컬럼을 N에서 Y로 변경하기 위해서는 같
은 비트맴 인텍스 키에 락을 걸어야 하기 때문이다. 또한 새로운 자료를 이 테이블에 입력하려는 다른
세션도 역시 일 처리를 할 수 없게 된다. 그것들 역시 동일한 비트맴 커에 락을 걸려고 하기 때문이다.
정리해보면, 개발지들은 기껏해야 동시 에 한 사람만 삽입하고 수정할 수 있는 테이 블을 생성한 것이었
다. 간단한예제를통해 쉽게 알수 있다.
I Note I 필자는 이 책에서 걸쳐 ‘락킹 (Iocking)’ 과 ‘블로킹 (blocking)’ , 그리고 동시성 이슈에 대해 예를 들어 보여줄 때
autonomous 트랜잭션을 사용할 것이다 밀자는 autonomous 트랜잭션이 개발자들에게 공개되어서는 안 되는 특징이라
믿는다. 왜냐하면 대부분의 개발자들은 이런 개념들을 언제 어떻게 적절하게 사용해야 하는지 모르기 때문이다
autonomous 트랜잭션을 부적절하게 사용하면 논리 데이터의 무결성이 깨지는 결괴를 가져올 수 있다 예시를 위한 도구가
아닌 다른 용도가 있다먼, 그건 오류 로깅밖에 없다‘ 그것은 ‘오류 로깅 메커니즘 (error-Iogging mechanism)’ 으로서 또
다른 용도를 갖는다. 만일 여러분의 프로그램 내의 예외 처리 블록에 오류 로그를 남기고 싶다먼, 오류를 테이블에 기록한
후 다른 어떤 테이블도 ‘커맛 (commit)’하지 않은 채 오류 로그 테이블만 커멋하면 된다. 이것은 autonomous 트랜잭션을
사용하는 쓸 만한 예가 될 것이다 만일 여러분이 autonomous 트랜잭션에 오류 로그를 남기고 어떤 개념을 설명하는 것
이외의 용도로 사용한다먼, 분명 뭔가 매우 잘못되었다고 할 수 있다.
여기서 필자는 동시성 관련 오류를 시연하기 위해 데이터베이스에서 하나의 세션에서 동시에 2개가 발
생하는 autonomous 트랜잭션을 사용할 것이다 autonomous 트랜잭션은 그 세션 내부에 이미 만들
어져 있는 트랜잭션과는 분리되고 구별된 ‘서브트랜잭션 (subtransacrtion)’ 을 시작한다 autonomous
트랜잭션은 마치 아주 다른 세션에서 실행된 것처럼 동작한다. 사실 부모 트랜잭션은 거의 중단된 것이
나 마찬가지다. 앞으로 살펴보겠지만 autonomous 트랜잭션은 부모 트랜잭션에 의해 블로킹될 수 있
으며 autonomous 트랜잭 션은 부모 트랜잭션이 만들고 커빗하지 않은 수정사항을 볼 수도 없다.
8
ops$tkyte%ORA11GR2>>> create table t
2 (processed_flag varchar2(1)
3 );
Table created.
ops$tkyte%ORA11GR2> create bitmap index
2 t_idx on t(processed_flag);
Index cr、eated.
ops$tkyte없RA11GR2> insert into t values ( ’N’ );
1 row created.
ops$tkyte%ORAllGR2> declare
2 pragma autonomous_transaction;
3 begin
4 insert into t values ( 'N ’ );
5 commit;
6 end;
7 /
declare
*
ERROR at line 1:
ORA.00060: deadlock detected while waiting for resource
O뻐 .06512: at line 4
• • • CHAPTER 01 성공적인 오라클 애을리케이션 개발
autonomous 트랜잭션을 사용하고 서브트랜잭션을 생성했을 때 ‘데드락 (deadlock)’ 이 발생했다. 두
번째 입력한 데이터가 첫 번째 입력한 데이터 때문에 막혀버린 것이다. 펼자가 만일 두 개의 세션을 사
용했다면, 데드락은 발생하지 않았을 것이다. 다만 두 번째 입력은 블로킹 상태가 되고, 첫 번째 트랜잭
션이 커빗되거나 롤백이 되기를 기다릴 것이다. 이러한 증상은 문제가 있는 프로젝트들이 직면히는 문
제들과 정확히 일치히는데, 바로 블로킹이나 직렬화 이슈다.
그래서 우리는 비트맹 인텍스와 같은 데이터베이스의 특정과 데이터베이 스의 동작방식을 이해하지 못
해 여러 가지 성능 이슈에 직면했고 처음부터 데이터베이 스의 확장성을 쓸모 없게 만들어버렸다. 이 렇
듯 복잡하게 꼬인 문제들을 해결하기 위해 이미 작성된 프로그램 코드들을 일일 이 조사할 수밖에는 없
었다. 데이터베이 스는 ‘큐 (queue)’ 와 관련된 내부 기능을 가지고 있는데 1997년에 처음으로 배포한
오라클 8.0 이후부터 가지고 있는 기능이다. 여러분은 이런 내장된 queuing 기능을 사용하며 많은 생
산자(처리되지 않은 레코드들을 나타내는 N값을 입력하는세션)가동시에 여러 메시지를 ‘입력 큐 (inbound
queue)’ 에 넣을 수 있도록 할 수 있고 소비자(처 리하기 위해 N으로 된 러l코드를 찾는 세션)가 동시에 이런
메시지들을 받을 수 있게 할 수 있다. 즉 데이터베이 스에서 큐 기능을 구현하기 위해 별도의 프로그램
코드를 만들지 말아야 했다. 개발자들은 데이터베이스에 내장된 기능을 사용했어야만 했다. 그러나 안
타깝게도 개발자들이 이런 개념을 애초부터 모르고 있었는지도 모른다.
다행히 도 이러한 종류의 문제들은 발견되기만 한다변 수정하기는 쉽다. 우리는 프로세스 처리 여부 플
9
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
래그를 갖는 결럼에 인텍스가 필요한데 비트뱀 인텍스로 만들면 안 된다. 아주 흔하고 생성하기도 쉬운
B*Tree 인텍스를 만들면 된다. 더 는 두 가지 종류의 값을 갖는 컬럼에 인텍스를 만드는 것이 성능상 유
리하다고 생각하는 분은 없으리라. 그러나 시물레이션(사실 펼자는 시율레이션이나 테 스트, 실험하는 것을
매우 좋아한다) 상에서 설 정한 후라면 비트맴 인텍스를 사용하는 데는 그리 문제가 되지는 않을 것이다
인텍스를 생성할 때 아래와 같은 접근 방식을 선택해야 했다.
· 프로세스처리 여부 플래그컬럼에 인텍스를 생성한다.
· 프로세스 처리 여부 플래그 컬럼 에 대하여 프로세스플래그가 N 일 때에만, 즉관심을 두는값에
대해서만 인텍 스를 생성하도록 한다. 우리는 프로세스 처리 여부 플래그가 Y인 것에 대해서 는 인
텍스를 생성하는 것을 원하지 않는다. 왜냐하면 테이블에 있는 값 대부분이 Y 일 것이기 때문이다.
필자가 ‘절 대 로안된다’는말을시용하지 않았다는점을기억하시길 여러분은여러 가지 이유로
종종 프로세스 플래그가 Y 인 것의 개수를 세기 를 원할 수도 있다 그땐 프로세스 플래그 Y 인 자료
에 대한 인텍스가 유용할 수도 있다.
인텍 스를 다루는 장에서 위의 두 가지에 관련해서 좀 더 자세히 살펴볼 것이다. 결국, 우리는 프로세스
처리 여부플래그가 N 인 컬 럼에 대해 매우작은 인텍스를 생성하였다. 자료 처리 속도를 매우빠르게
할 수 있었고, 대부분의 Y값은 이 인텍 스에 영향을 미치지 않았다. 우리는 N값이나 NULL :값도 반환하
기 위해 함수 decode( processed_flag, ’N’, ’N’)로 함수 기반 인텍 스를 사용하였다. 전체 NULL값은
B*Tree 인텍스에는 들어가지 않기 때문에 위의 함수를 사용하였고, 결국 우리는 N값에 대한 인텍스만
생성하게 되었다.
이 것으로 모든 문제가 해 결 되었을까? 전혀 그렇지 않았다. 필자의 고객이 가진 해 결책은 여전히 최적
이 아니었는데 , 왜냐하면 처리 여부가 N 인 데이터 를 큐에서 꺼내는 처리를 직렬로 수행해야만 했기 때
문이다. 프로세 스가 되지 않은 첫 번째 자료를 select * from queue_table where decode (
processed_flag, ’N’, ’N’) = ’N’ FOR UPDATE 쿼리를 사용해서 쉽게 찾을 수 있었다 그러나 한 번에
한 개의 세션만 사용 가능한 문제가 있었다. 그 프로젝트는 오라클 10g를 사용하고 있었기에 오라클
l1g 릴 리즈 1 에 추가된 SKIP LOCKED 기능을 사용할 수 없었다 SKIP LOCKED 기능은 많은 세션
이 처음 찾은 아직 처리되지 않은 값의 자료를 찾고 그 데이터에 락을 걸고 그것을 동시에 처리할 수
있게 한다 그 기 능 대신에 우리는 처음에 락이 풀린 데이터를 찾아 그것에 수동으로 락을 걸어주는 프
로그램을 구현해야만 했다. 오라클 10g 이전 버전에서 는 다음과 같은 방법으로 구현한다. 펼요한 인텍
스를 가진 테이블을 만들고 샘플 데이터 를 채웠다.
ops$tkyte%ORA11GR2> create table t
2 (ìd number primary key,
10
3 processed_flag varchar‘2(1) ,
4 payload varchar2(20)
5 ) j
Table created.
ops$tkyte%ORA11GR2> create index
2 t idx on
3 t( decode( processed_flag, ’ N' ’ 'N ’ ) )j
Index created.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA1 1GR2> insert into t
2 select r,
3 case when mod(r ,2) = 0 then ’N’ else 'Y ' end,
4 ’ payload ' :: r
5 from (select level r
6 from dual
7 connect by level <= 5)
8 /
5 rows created.
ops$tkyte%ORA11GR2> select * from tj
ID P PAYLOAD
1 Y payload 1
2 N payload 2
3 Y payload 3
4 N payload 4
5 Y payload 5
• • CHAPTER 01 성공적인 오라클 애을리케이션 개발
그 다음 모든 프로세스 처리 여부 플래그가 N 인 자료를 찾을 필요가 있다. 모든 자료 하나하나에 대해
“이 로우가 이미 락이 걸려 있는가? 그렇 지 않다면 그 자료에 락을 걸고 결과를 보여달라”는 요청을 했
다. 다음의예를보자
ops$tkyte%ORA11GR2> create or replace
2 function get_first_unlocked_row
3 return t%rowtype
4 as
5 resource_busy exceptionj
6 pragma exception_init( resource_busy, .54 )j
11
전문가를 위한 오라클 데이터베이스 아키텍처 • •
7 l_rec t%ro빠ype;
8 begin
9 for x in ( select rowid rid
10 from t
11 where decode(processed_flag, 'N') ’N’) = ’ N' )
12 loop
13 begin
14 select * into 1 rec
15 from t
16 where rowid = x.rid and processed_flag= ’N'
17 for update nowait;
18 return lJec;
19 exception
20 when resource_busy then null;
when no_data_found then null;
21 end;
22 end loop;
23 return null;
24 end;
25 /
Function created.
I Note I 위의 코드에서 필자는 몇 개의 DDL 명령어 (CREATE 또는 REPLACE)를 수행했다. DDLOI 수행되기 바로 직전에
자동으로 커맛이 된다‘ 이것은 묵시적으로 커맛이 된다는 것을 의미한다 다음 예제를 제대로 처리하기 위해서는 데이터베이
스에 입력한 로우를 커맛하여야 한다 일 반적으로 필자는 이 책의 뒷부분에서 이 내용을 사용할 것이다. 만일 여러분이
CREATE 또는 REPLACE를 수행하지 않고 이러한 예제들을 실행한다면 가능한 한 먼저 커맛을 확실하게 실행해야 한다-
우리가 두 개의 서로 다른 트랜잭션을 사용하면 다음과 같은 두 개의 각각 다른 자료를 볼 수 있을 것
이다. 또한 두 개의 서로 다른 자료를 동시에 볼 수 있다(동시성 이슈에 대한 예를 보여주기 위해서 한 변 더
autonomous 트랜잭션을 시용한다).
ops$tkyte영RA11GR2> declare
2 l_rec t%rowtype;
3 begin
4 l_rec := get_first_unlocked_row;
5 dbms_output.put_line( '1 got row ‘ :: lJec.id :: ’ , ’ :: lJec.payload );
6 end;
7 /
1 got row 2, payload 2
PL/SQL procedure successfully completed.
12
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
ops$tkyte뻐RA11GR2>
ops$tkyte%ORA11GR2> declare
2 pragma autonomous_transactionj
3 l_rec t%rowtype;
4 begin
5 l_rec := get_first_unlocked_row;
6
7
8 endj
9 /
dbms_output.put_line( '1 got row. ' :: l_rec.id :: ‘ , ’ : : lJec.payload );
commit;
1 got row 4, payload 4
PL/SOL procedure successful1y completed.
오라클 l1g 릴라즈 1 이 후 환경에서는 위의 로직 에 SKIP LOCKED 문장을 추가로 사용하여 만들 수
있다. 다음 예제에서 두 개의 동시 트랜잭션을 만들고, 각 트랜잭션이 독립적으로 자료를 동시 에 찾고
락을 건다는 사실을 확인할 수 있다.
ops$tkyte뼈RA11GR2> declare
2 l_rec t%rowtype;
3 cursor c
4 is
5 select *
6 from t
7 where decode(processed_flag, ‘N’ ,'N') 'N’
8 FOR UPDATE
9 SKIP LOCKED;
10 begin
11 open c;
12 fetch c into l_rec;
13 if ( c%found )
14 then
15 dbms_output.put_line( '1 got row ' :: lJec.id :: ’ , ’ 끼 lJec.payload );
16 end ifj
17 close c;
18 end;
19 /
1 got row 2, payload 2
PL/SQL procedure successfully completed.
ops$tkyte%ORA11GR2>
ops$tkyte%ORA11GR2> declare
2 pragma autonomous_transactionj
3 l_rec t%rowtype;
13
위에 소개한 두 가지 해결 방법은 고객이 메시지를 처리할 때 가지고 있던 두 번째 직렬화 문제를 해결
하는 데 도움을 줄 것이다. 고객이 Advanced Queuing과 DBMS_AQ.DEQUEUE를 호출해서 사용
했다면, 둘중어떤솔루션이 더 쉽겠는가?처리해야할메시지들에 대하여 직렬화문제를해결하는것
과 자료를 추출하기 위해 ‘함수 기반 인텍스 (function-based index)’ 를 구현하고 프로그램 코드를 개발
해야 했다. 결론적으로 잠재하던 중대한 문제를 해결했다. 이 문제들은 개발지들이 사용하고 있는 툴에
대한 정확한 이해가 없었기 때문에 발생한 것이긴 하지만 시스탬이 제대로 구축된 것이 아니므로 많은
조사와 연구가 필요했다. 아직 해결하지 못한 이슈가 남아 있다.
• 애플리케이션에 데이터베이스 레벨 (database leveI)로의 확장성에 대한 고려가 전혀 없었다.
• 데이터베이스가 이미 내부적으로 가지고 있는 높은 수준의 동시성 및 확장성을 제공하는 큐 테이
블과 같은 기능을 애플리케이션에서 따로 만들어서 수행하고 있었다.
• 펼자의 경험에 비추어 볼 때 80-90% 정도의 튜닝은 데이터베이스 레벨이 아닌 애플라케이션 레벨
에서 이루어진다.
• 개발자들은 데이터베이스 내에서 자바 컴포넌트가 무엇을 하는지 몰랐으며, 잠재한 문제를 어디서
찾아야할지몰랐다.
앞에 열거한 내용만이 이 프로젝트가 가진 문제의 전부는 아니다 다음과 같은 또 다른 문제를 해결해
야했다.
14
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
. SQL을 바꾸지 않고 어떻게 SQL을 튜닝할 것인가? 일반적으로 매우 힘든 작업이다. 오라클 10g
이상에서는 SQL Profile을 가지고 이런 마술을 부릴 수 있는 기능을 어느 정도 제공한다. 오리클
l1g 이상부터는 확장된 통계 기능을 사용해서 이런 일을 할 수 있다. 그러나 그렇다고 비효율적인
SQL 이 이런 기능을 이용하여 효율적인 SQL로 탈바꿈하는 일은 없다.
• 어떻게 성능을 측정할 것인가?
• 어디서 병목현상이 발행히는지 어떻게 찾을 것인가?
• 어떻게, 무엇에 대해 인텍스를 생성할 것인가 등등이다.
며칠이 지나서, 데이터베이 스를 모르고 있던 개발자들은 데이터베이스가 실제로 제공하는 기능이 무엇
인지, 그리고 그것을 쉽게 배울 수 있다는 것을 알고 경악을 금치 못했다. 가장 놀라워했던 것은 그들이
데이터베이 스의 기능이 가진 장점을 시용하는 것이 애플리케 이션의 성능에 얼마나 큰 긍정적인 영향을
미치는지를 알았다는 것이다. 결국 예정보다 2주 늦었지만 프로젝트는 성공적으로 마칠 수 있었다.
데이터베이 스 기능 활용에 대해 이야기한다고 해서 여러분이 사용하는 툴이나 하이벼네이트
(Hibema te), EJB나 컨테이너 관리 유지와 같은 기능들에 대해 비판하는 것은 아니다. 데이터베이스와
그것의 작동 원리와 사용법에 대해 개발자들이 시간을 투자하여 공부하려 하지 않는다는 것을 비판하
는 것이다 이번 프로젝트에서 사용했던 기술은 개발지들이 데이터베이 스의 원리에 대해 몇 가지를 이
해한 후에좀더잘작동되었다.
일반적으로 데이터베이스가 여러분이 개발한 애플리케이션의 초석이 되어야 한다는 것이 요점이다. 데
이터베이스가잘작동하지 않는다면 다른 어떤 것도 핵심 문제가되지 않는다. 만일 여러분이 블랙박스
를갖고 있는데 그것이 작동하지 않는다면 여러분은무엇을할수 있겠는기-? 여러분이 할수 있는유
일한 일은블랙박스를보면서 “왜 잘작동하지 않지?’라며 궁금해하는 일만할수 있을뿐이다. 블랙박
스를 고칠 수도, 튜닝할 수도 없다(역자 주- 물론 고급 엔지니어나 DBA는 데이터베이스를 튜닝할 수는 있지만,
일반 개발자들에게는 그림의 떡일 뿐L 쉽게 말해 블랙박스가 어떻게 일하는지 이해할수 없다는 것이다.
대안은 필자가 주장히는 접근법을 사용하는 것이 다. 여러분이 사용하는 데이터베이스를 이해하라. 어
떻게 일하는지 알고, 여러분을위해 어떤 일을할수 있는지 알고 가능한데이터베이스가갖춘모든능
력을시용하라.
데이터베이스 애플리케이션 개발 방법
지금까지는 가설을 세워 설명한 것으로 충분했다. 이번 장의 남은 부분에서는 좀 더 경험적인 접근을
통해 왜 데이터베이스에 대해 아는 것이 애플리케이션을 두 번 개발하지 않고 성공적인 개발에 큰 도움
이 되는지 토론할 젓이다. 몇 가지 문제점들은 발견되기만 하면 곧바로 손쉽게 수정될 수 있다. 물론 어
15
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
떤 문제들은 기슴이 아프지만 새로 재개발을 해야 할지도 모른다. 이 책을 쓴 목적 중 하나는 여러분이
이런문제 때문에 받을피해를처음부터 피할수있도록도웅을주는것이다.
I Note I 다음 절에서는 몇몇 오라클의 핵심 기능들에 대해 간단히 이야기하겠다 이 기능들을 자세히 소개하거나 소개한
기능들을 사용해서 얻을 수 있는 결괴물에 대해서는 이 책의 나머지 부분에서 다룰 것이 며 더 자세한 정보를 위해서 관련
오라클 문서를 소개할 것이다
오라클아커텍처의 이해
필자는 대규모 애플리케이션을 운영하는 여러 고객을 위해 일했었는데 그곳의 애플리케이션은 SQL
서버와 같은 이기종의 데이터베이스로부터 오라클로 ‘이식 (migration)’ 된 것들이었다 일단 ‘이식’ 이
라는 단어를 인용부호로 묶었다. 왜냐하면 펼자가 알고 있는 대부분의 이식은 ‘SQL 서버 코드를 컴파
일하고 오라클에서 실행할 수 있도록 만들기 위한 최소한의 변경 대상이 무엇인가’ 라는 관점에서 이루
어졌기 때문이다. 솔직히 그런 생각으로 이미 만들어진 애플라케이션을 많이 관찰하는 이유는 이런 유
형의 애플라케이션에서 더 많은 문제가 발생했기 때문이다 이런 이유에서 (역자 주 SOL 서버에서 오라클
로 이식한 애플리케이션에서 오류가 많다는 이유) SQL 서버가 나쁘다고 말하는 것은 결코 아니다. 그 반대의
경우에도 똑같은 문제가 발생하기 때문이다. 오라클 환경에서 개발한 애플리케이션을 몇 가지 바꾸지
도 않은 채 SQL 서버 위에 풍탕 떨어뜨려 놓는다면 똑같이 많은 성능 문제가 발생할 것이다. 양쪽 다
같은 문제가 발생한다는 것이다.
그러나 어떤 경우 SQL 서벼 아커텍처와 SQL 서벼 사용 방법의 문제는 오라클로 이식히는 일에 큰 영
향을 미쳤다. 이렇게 장황하게 설명하는 주된 목적은 데이터베이스 서벼 간의 확장성을 높이는 것이지
만, 사람들은 다른 데이터베이스로의 ‘효과적인 이관’ 이 주된 요구사항은 아니다 그들이 원하는 것은
최소한의 작업으로 데이터 를 옮기는 것이고, 클라이언트와 데 이터베이스 레이어에서 많은 수정을 하지
않고도 SQL 서버에서와 같은 방식의 아키텍처 를 사용할 수 있도록 하는 것이다 이런 결정은 두 가지
중요한결과를냈다
• SQL 서벼에서 사용하는 DB 연결(혹은 DB 커 넥션) 아키텍처를 그대로 오라클에서 사용하였다.
• 개발자들은 리 터 럴 (literal) SQL을 사용하였다.
이런 두 가지 점 (역자 주→ 커넥션 아키텍처의 흔용과 리터릴 SOL의 사용) 때문에 시스템은 사용자의 부히를
견디지 못하고 가용한 모든 메모리를 소모해버렸고 매우 심각한 성능 문제가 발생했다
싱글커넥션을사용하라
최근에는 일반적으로 SQL 서버에서는 데이터베이 스에서 동시에 실행되는 각각의 쿼리에 대해 하나의
16
• • • CHAPTER 01 성공적인 오라클 애를리케이선 개발
커넥션을 독립적으로 연다. 여러분이 5 개의 쿼리를 수행한다면 아마도 5개의 커넥션을 만드는 것을 보
게 될 것이다. 그렇지만오라클에서는 5개의 쿼리를수행하든 5 백 개의 쿼리를수행하든 1 개의 컨넥션
만 유지한다. 따라서 SQL 서버에서는 일반적인 방식이 오라클에서는 추천할 수 없는 방식이 되고 만
다 오히려 이런 방식은 절대 채택해서는 안 되는 접속 방식인 것이다. 오라클에서는 다중 커넥션을 절
대로 만들지 말아야 한다.
그러나 안타깝게도 개발자들은 하지 말라는 방식을 사용하고 있다. 간단한 웹 페이지 하나에 5, 10, 15
혹은 그 이상의 커넥션을 맺고 있는데, 데이터베이스 측면에서 보면 동시 사용 기능한 시용자수를 1/ 5,
1/10 또는 1 / 15로 줄이게 되는 것과 똑같이 되는 것이다. 게다가 그들은 오리클을 윈도우즈 ‘데이터
센터’ 벼전에서 돌리는 것도 아니고 평범한 윈도우즈 서버 플랫폼에서 돌리려 한다. 윈도우즈 싱글 프
로세스 아카텍처는 오라클 데이터베이스가 사용할 수 있는 메모리의 최대 크기를 175GB까지만 허용
한다. 각각의 오라클 커넥션은 일정한 양의 메모리 공간이 필요하기 때문에 해당 애풀리케이션을 시용
해서는 시용자 수를 확장하는 데 심각한 제약을 받을 수밖에 없게 되었다. 서버에는 물리적으로 8GB 의
메모리를 가지고 있었지만, 실제 사용 기능한 것은 2GB밖에 되지 않았다.
I Note I 32비트 윈도우즈 환경에서 /AWE 스위치를 사용하여 더 많은 램을 사용하는 방법이 있기는 하지만, 이런 환경에
서는 /AWE 스위치를 쓸 필요가 없는 다른 버전의 운영체제를 사용해야 한다
이런 문제의 해결책으로 세 가지 접근방법이 있었다. 이 세 가지 방법은 매우 간단한 작업이어서, ‘이
식’ 이 완료된 후 사용했다 이 옵션들은 다음과 같다.
• 오라클의 장점을 최대한 활용할 수 있도록 애플라케이션의 아키텍처를 다시 구성하도록 하자 한
페이지를 생성하는 데 5개에서 15 7H 의 커넥션을 사용하지 말고 1 개의 커넥션만 사용하도록 한다
이것은 이 문제 (역자 주- 동시 접속자의 수 제한 문제)를 실제로 해 결할 수 있는 유일한 해법이다.
• 운영체제를 업그레이드하고 윈도우즈 데이터 센터 버전을 사용해서 대용량의 메모리 모델을 사용
하라. 이 부분은 간접적인 데이터 버퍼와 비표준적 설정을 사용해야 하는, 다소 복잡한 데이터베이
스설정 이 필요하므로결코간단한일은아니다.
• 윈도우즈 기반 운영체제에서 다중 프로세스가 사용되는 운영체제로 데이터베이스를 이관할 경우,
데이터베이스가 가용한 모든 메모리를 사용하도록 작업하라 32 비트 윈도우즈 플랫폼에서는
PGA/SGA 영역을합해 모두 2GB까지의 메모리를사용할수 있다. 두 개의 영역은한개의 프로
세스로 인식되기 때문이다. 디중 프로세스 플랫폼에서는 같은 32 비트라도 SGA에 2GB와 PGA에
2GB 씩 각각 사용할수 있다 32 비트 윈도우즈 플랫폼보다 더 많은 메모리를 사용할 수 있는 것이다.
• 여러분이 직접 실행해보면 알겠지만, 위에서 말한 어떤 것도 “좋아, 이건 한나절 작업이야”라고 할
17
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
만한 것은 없다. 각각의 것들은 복잡한 해법을 가지고 있다. 데이터베이스 이관 단계에서라면 쉽게
수정될 수 있는 문제다. 프로그램 코드를 개발하고 초기에 그것들을 수정하는 단계라면 더더욱 그
렇다. 또한 프로젝트를 오픈하기 전 간단한 확장성 테스트만 한다면 고객들이 앞으로 발생할 문제
때문에 괴로워하기 전에 미리 발견할 수 있는 종류의 문제일 것이다.
바인드 변수를사용하라
필자가 ‘확장성이 전혀 없는 오라클 애플라케이션 만들기’ 라는 책을 쓴다면 1장과 마지막 장은 ‘바인
드 변수를 사용하지 마라’ 는 주제로 쓸 것 이다. 바인드 변수를 시용하지 않는 것은 성능과 확장성과 관
련하여 매우 중요한 문제다. 물론 보안의 위험도 크게 따른다는 것은 말할 것도 없다. 개발자들이 바인
드 변수만 사용한다면 대부분은 오라클 shared pool (매우 중요한 공유 메모리 데이터 구조)의 작동 방식을
명확하게 할수 있다. 만일 오리클을느려 터져서 거의 서 있는지경으로만들고 싶다면, 그방법은아
주 간단하다. 바인드 변수를 사용하지 않으면 된다.
바인더 변수는 쿼리에 있어서 플레이스 홀더 (역자 주_ placeholder, 빠져 있는 것을 대신하는 기호)다. 예를
들어 직원 123을 조회하기 위해 다음과 같은 쿼리를 할 수 있다.
select * from emp where empno = 123j
다른 방식으로는 이렇게도 쿼리할 수 있다.
select * from emp where empno = :empnoj
일반적인 시스템에는 사원번호 123을 한 번 조회하고 끝나고, 다음으로 사원번호 456을 조회하고, 그
다음엔 789를 조회하는 식이다 (역자 주- 세 개의 사원번호를 조회하기 위해 세 개의 서로 다른 Literal SQL을
실행한대. 아니면 위에 말한 SELECT 문장들처럼 인서트 문을 시용하는데 바인드 변수를 시용하지 않
으면 기본 키 값 (empno) 이 문장 안에 하드 코딩될 것이다. 그리고 인서트 문장은 다시는 재사용될 수
없을 것이다 (역자 주- 물론 누군가가 세 개의 사원번호와 동일한 사원변호를 입력하여 조회한다면 재사용될 것이지
만), 쿼리 안에 상수를 대입하여 사용하면 데이터베이 스는 모든 쿼리를 새로운 쿼리로 인식하여 파싱
하고, 문법을 검사하고, 보안을 체크하고, 옵티마이징하는 등의 일을 할 것 이다(역자 주- 이런 절차를 하
드 따싱이라 한대. 즉 모든 쿼리가 실행될 때마다 다시 컴파일 되어야 한다는 말이다.
두 번째 쿼리는 :empno 라는 바인드 변수를 시용했다 :empno 값은 쿼리가 실행될 때마다 주어진다.
이 쿼리는 한 번 컴파일이 된 후 shared pool (라이브러리 캐시)에 저장되며, 동일한 쿼리가 실행될 때
shared pool에서 가져와 재사용될 수 있다. 성능과 확장성의 관점에서 두 가지 방식의 차이는 극적일
정도로엄청나다.
18
. . .. CHAPTER 01 성공적인 오라클 애을리케이션 개발
위의 설명에서, 하드 코딩된 변수가 포함된 문장을 파성하는 것(하드 파스)은 이미 파싱된 쿼랴 플랜(소
프트 파스)을 재사용하는 것보다 더 많은 시간과 더 많은 자원을 소비한다. 하드 파스 시스탱이 제공하
는 사용자 수를 어느 정도까지 줄이는지는 분명치 않다. 분명한 것은, 이것은 부분적으로 자원 소비가
증가되었기 때문에 발생하며 좀 더 중요한 요인을 찾자면 라이브러리 캐시의 ‘래지 메커나즘 (latching
mechanism)’ 때문에 발생하는 것이다. 쿼리를 하드 파스할 때, 데이터베이스는 ‘래치 (!atches)’ 라고 부
르는 로우 례 벨의 ‘직 렬화 장치 (serialization device)’ 를 좀 더 길게 붙잡고 있게 된다(좀 더 자세한 내용응
락킹과 래칭 (Locking and Latching)을 다루는 장을 참고하길) . 이런 래치는 오라클의 공유 메모리 내부에서
두 개의 세션이 동시에 통일한 데이터를 수정하려 할 때 수정 중인 데이터를 읽을 때 데이터를 보호하
는 역할을 한다(이것이 없다면 오라클은 데이터 손상을 입을 것이다) 더 길게 그리고 더 지주 이러한 데이
터의 구조를 래치할수록, 이런 래치를 가져오는 큐는 더 긴 시간을 소비하게 될 것이다. 결국 부족한 자
원을 독점하기 시작하여 서버가 가끔 제대로 돌지 않는 것처럼 보일 수 있다. 그러나 실제로는 데이터
베이스의 모든 기능들이 매우 느리게 동작하고 있는 것이다. 누군가가 이런 직렬화 장치를 잡고 쿼리가
파싱되고 있기 때문에 느려지는 것이다. 이런 경우에는 최상의 애플리케이션 속도를 기대할 수 없다.
잘못 동작하는 애플리케이션 하나만으로도 애플리케이션의 성능에 큰 영향을 마 칠 수 있다. 바인드 변
수를 사용하지 않는 한 개의 작은 애플리케이션은 그것과 상관없어 보이는 잘 작성된 다른 애플라케이
션이 shared pool을 사용하지 못하게 하는 원인이 될 것이다. 썩은 사과 하나가 바구나 전체의 사괴를
망친다.
만일 바인드 변수를 사용한다면 통일한 오브젝트를 참조한 동일한 쿼리를 사용하여 실행할 경우에
shared pool에서 컴파일된 실행계획을 참조한다. 여러분은 서브루틴을 한 번만 컴파일하고 계속해서
재시용하면 되며, 이것이 가장 효율적인 방법일 뿐 아니라 데이터베이스 측면에서 사용자가 이런 식으
로 개발하도록 추천하는 방법이다. 여러분은 더 적은 자원을 사용할 뿐 아니라(소프트 파스가 더 적은 자
원을 차지함), 래치를 더 적은 시간 동안 점유하고 사용시간을 줄일 수 있도록 요구할 것이다. 바인드 변
수를 사용하는 것이 성능을 향상시키고 확장성을 크게 높여줄 것이다.
이제 성능 관점에서 바인드 변수의 사용 여부가 결과에 얼마나 큰 차이를 가져올 수 있는지를 간단한
테스트를 통해 알아보고자 한다. 이 태스트에서 한 개의 테이블에 약간의 데이터를 넣을 것이다. 태이
블은다음과같다.
ops$tkyte%ORA11GR2> create table t ( x int );
Table created.
두 개의 간단한 저장 프로시저를 생성했다. 두 개의 프로시저 모두 다 테이블에 1 에서 10 , 000까지 입력
할것이다. 첫 번째 프로시저는바인드 변수를사용한 SQL 문을시용했다.
19
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
ops$tkyte%ORA11GR2> create or replace procedure proc1
2 as
3 begin
4 for i in 1 .. 10000
5 loop
6 execute immediate
7 ’ insert into t values ( :x )' using i;
8 end loop;
9 end;
10 /
Procedure created .
두 번째 프로시저 는 입력되는각로우마다각각다른 SQL 문이 실행되도록하였다.
ops$tkyte%ORA11GR2> create or replace procedure proc2
2 as
3 begin
4 for i in 1 .. 10000
5 loop
6 execute immediate
7 ’ insert into t values ( ’ : :i: : ’ ) ' ;
8 end loop;
9 end;
얘/
Procedure created.
위 두 프로시저의 차이점은 바인드 변수를 사용한 것과 그렇지 않은 것과의 차이다. 둘 다 동적 SQL을
사용했으며 로직은동일하다. 즉 바인드 변수의 사용 여부에만차이가 있다. 이제 두 가지 처리 방법에
대한 성능 평가를 해보자. 두 개 의 결과물을 비 교하기 위해 필자가 개발한 runstats라는 툴을 사용할
것 이다.
I Note I runstats와 다른 유틸리티에 대한 자세한 설명은 부록의 Tools & scripts를 참고하기 바란다
20
ops$tkyte%ORA11GR2> exec runstats-pkg.rs_start
PL/SQL procedure successfully completed.
ops$tkyte%ORA11GR2> exec proc1
PL/SQL procedure successfully completed.
ops$tkyte%ORA11GR2> exec runstats-pkg.rs_middle
PL/SOL procedure successfully completed.
ops$tkyte%ORA11GR2> exec proc2
PL/SOL procedure successfully completed.
ops$tkyte없RA11GR2> exec runstats-pkg.rs_stop(10000)
Run1 ran in 65 cpu hsecs
Run2 ran in 1224 cpu hsecs
run 1 ran in 5.31% of the time
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
I Note I 여러분은 CPU에 관련해서 여기에서 보여준 것과 정확히 같은 값을 보진 못할 것이다 오라클 버전의 차이, 운영
체제의 차이 또는 하드웨어 플랫폼의 차이로 인해 이러한 차이가 야기될 것이다 결과는 같지만, 정확한 숫자들은 분명히 미
미하게 차이가 날 것이다
아래에서 제시할 결과는 CPU time 에 근거해서, 바인드 변수를 시용하지 않은 것이 바인드 변수를 사
용한 것에 비해 10.000개의 로우를 입력하는 데 훨씬 긴 시간이 필요하고, 훨씬 더 많은 자원을 차지한
다는 것을 명백하게 보여준다. 바인드 변수 없이 로우들을 입력하면 CPU time 이 약 20배나 더 소모되
었다. 바인드 변수를 사용하지 않은 채 매번 입력 작업을 수행함에 있어 문장듬을 단순히 파싱하는 데
만 막대한 시간을 소모하는 것을 확인할 수 있다. 그런데 이런 정보에 오류가 일부 포함된다. 또 다른
정보를 참고해보면, 우리는 각각의 접근법에 사용되는 자원별로 중요한 차이점을 알 수 있다.
Name Run1 Run2 Diff
STAT ... parse count (hard) 5 ‘ 10,010 10,005
STAT ... parse count (total) 34 10,055 10,021
STAT ... consistent gets from ca 78 10,120 10,042
STAT ... consistent gets 135 10,290 10,155
STAT ... consistent gets from ca 135 10,290 10,155
LATCH.simulator hash latch 83 10,990 10,907
STAT ... db block gets from cach 10,440 30,364 19,924
STAT ... db block gets 10,440 30 ,364 19,924
STAT ... db block gets from cach 79 20,041 19,962
LATCH.enqueues 40 20 ,372 20,332
LATCH.enqueue hash chains 74 20,414 20,340
STAT ... session logical reads 10,575 40,654 30 ,079
STAT ... recursive calls 10,326 40,960 30 ,634
LATCH.kks stats 23 65 ,141 65 ,118
STAT .. . session uga memory @ 65,512 65,512
STAT ... session pga memory 0 65,536 65 ,536
LATCH.cache buffers chains 51 ,532 120,773 69 ,241
LATCH. shared pool simulator、42 104,558 104,516
21
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
LATCH.row cache objects
LATCH.shared pool
294 184,697 184,403
20 ,302 446 ,397 426 ,095
LATCH .JS slv state obj latch 435 ,890 435 ,889
Run1 latches total versus runs .. difference and pct
Run1 Run2 Diff Pct
73 ,082 1,411 ,695 1,338 ,613 5.1 8%
PL /SOL procedure successfully completed.
runstats 유릴리티는 통계에서의 차이뿐 아니라 래치 사용에서의 차이점도 보여주는 리포트를 생성한
다. 필자는 runstats를 이용하여 10000보다 더 큰 차이점을 보여주는 모든 항목을 출력하도록 했다.
바인드 변수를 사용한 첫 번째 방법은 4번 하드 파스를 했고, 바인드 변수를 시용하지 않은 것은 입 력
하는 문장마다 한 번씩 10000 변 하드 파스를 했다는 것을 알 수 있다. 그러나 하드 파싱 항목의 차이는
단지 빙산의 일각일 뿐이다. 여기서 바인드 변수를 시용하지 않는 방법은 바인드 변수를 사용하는 것보
다 거의 20배 정도의 래치를 사용했다는 것을 알 수 있다. 이런 차이점을 본다면 래치가 무엇인지 궁금
해질것이다.
이 질문에 대한 답을 해보겠다. 래치는 오라클이 사용하는 공유 데이터 구조에 ‘직렬화 접근 (serialize
access)’ 을 하기 위해 사용되는 락의 일종이다. 공유 풀 (shared pool)이 이런 구조에 대한 한 가지 예가
된다. shared pool은 System Global Area (SGA) 에 존재하는 매우 큰 공유 데이터 구조며, 오라클이
해석하고 검파일한 SQL을 저장히는 공간이다 이런 공유 구조를 수정하려면, 한 번에 한 개의 프로세
스만 허용되어야 할 것이다(만일 두 개의 프로세스나 쓰레드가 같은 메모리 데이터 구조를 동시에 갱신하려 한
다면, 이것은 매우 나쁜 상황에 직면하게 된다. 많은 데이터에 손상이 발생하게 될 것이다). 그래서 오리클은 래
치 메커니즘, 즉 처리를 직렬회-시키는 경량의 락킹 메커니 즘을 채택했다. 경량이라는 단어에 속지 말
자. 래치는 한 번에 한 개의 접근만 허용하게 하는 직렬화 장치다. 위에서 사용되는 래치 대부분은 하드
파스를 수행할 때 사용되는 래치다 이것들은 공유 풀과 라이브러리 캐시를 위해 사용되 는 래치를 포함
하고 있다 이런 래치 들은 사람들이 자주 경쟁하듯 사용히는 긴 시간의 래치들이다. 동시에 여러 개의
문장을 하드 파스하는 사용자의 수가 증가할수록 성능은 점진적으로 나빠진다는 것을 의미한다. 더 많
은 사람이 파싱을 하면 할수록 더 많은 사람이 공유 풀의 래치를 획득하기 위해 기다리게 되고, 큐에 대
기하는 것이 더 길어져 대기 시간이 더 길어진다.
바인드 변수 없이 SQL 문을 실행하는 것은 메 서드를 호출하기 전 에 서브루틴을 컴파일하는 것과 매우
비슷하다. 클래스 안에서 메서드를 호출하기 전에 자바 소스 코드를 고객에게 이관해준다고 상상해보
자 고객들은 자바 컴파일러를 작동시켜 클래스를 컴파일하고, 메서드를 실행한 후에 바이트 코드를 던
져준다. 그 후에 똑같은 메서드를 실행하려고 하면 위의 일을 똑같이 해야 한다. 컴파일하고, 메서 드를
22
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
실행하고, 바이트 코드를 던져주는 식으로 말이다. 여러분은 애플라케이션을 절대 이렇게 만들지 않을
것이다. 데이터베이스도 이런 식으로 동작하도록 만들면 안 된다
바인드 변수를 사용하지 않아서 발생하는 또 다른 영향(개발자들이 변수에 상수를 결합하여 실행하는 것)은
바로 보안이다. 특별히 SQL injection이라고 불리는 문제에 노출된다. 이 용어가 생소하다면 잠시 이
책을 덮어두고 검색엔진을 사용해서 SQL injection을 찾아보기 바란다 이 글을 쓰는 지금 거의 백만
변의 조회 수가 있는 유명한 검색어다. SQL injection에 관련된 문제는 문서화가 잘 되어 있으니 참고
하기바란다
I Note I SOL injection은 개발자가 고객으로부터 상수를 입력받아 원래의 쿼리에 결합시켜서 검파일하고, 그 쿼리를 실행
할 빌미를 제공하는 보안의 구멍이다. 결과적으로 개발자는 고객으로부터 SOL 코드 조각을 받아서 킴파일하고 실행하는
것이 된다 이러한 방법은 고객이 SOL 문을 수정해서 개발자가 의도하지 않는 방항으로 애플리케이션을 조ξ면fJil 힐 위힘
을 안고 있는 것이다 이것은 SYSDBA로 접속하여 로그인한 채 SOL*Plus 장을 열어놀고 자리를 뜨는 것과 같다 제발 누
군가가 와서 명령어를 입력하여 컴파일하고 실행하라고 요정하는 것과 같다 그 결과는 처참할 수도 있다
여러분이 바인드 변수를 시용하지 않고 PROC2에서 전에 보여준 것처럼 문자열 결합 기술을 시용하여
개발한다면, 여러분이 개발한코드는 SQL injection 공격에 노출되 기 때문에 반드시 꼼꼼하게 살펴보
아야 할 것이다. 물론 리뷰는 프로그램 개발자를 좋아하지 않는 사람들이 하는 것이 좋다. 비판적이고
객관적인 리뷰가 필수적이기 때문이다. 혹시 라뷰어가 개발자의 동료이거나 심지어 친구나 부하직원
이라면 리뷰가 제대로 이루어질 수가 없을 것이다 (역자 주 역자의 경힘상 필은 안으로 굽는다l. 개발된 프
로그램 코드가 바인드 변수를 사용하지 않은 것이 있는지 자세히 살펴보아야 한다. 바인드 변수를 사용
하지 않는 것은 예외적인 경우에만 허용되어야 하며, 아주 일반적인 경우에는 허용되어서는 안 된다.
다음의 짧은 예를 통해 SQL injection 이 얼마나 나쁜 영호上을 미치는지 살펴보겠다.
ops$tkyte%ORA11GR2> create or rep1ace procedure inj( p_date in date )
2 as
3 1Jec all_users%rowtype;
4
5
6 begin
7
8
9
10
11
12
13
14
c sysJefcursor‘;
1_ query 1ong;
l_query := ’
se1ect *
from all users
where created "': :p_date :: '" ’ ;
dbms_output.put_1ine( l_query )j
open c for l_query;
23
전문가를 위한 오라클 데이터베이스 아키택처 • • •
15 for i in 1 . . 5
16 loop
17 fetch c into lJec;
18 exit when c‘~notfound;
19 、dbms_output.put_line( l_rec.username :: ' ‘ );
20 end loop;
21 close c;
22 end;
23 /
Procedure created.
I Note I 이 코드는 기껏해야 5개의 레코드를 출력한다 이것은 ‘빈 (e mply)’ 스키마에서 실행되도록 개 발하였다, 많은 테이
블을 보유한 스키마에서는 아래에 보여줄 결과오는 다른 다앙한 결과들을 얻을 수도 있다 이 예제에서 보여주고자 하는 테
이블을 볼 수 없을지도 모른다는 뜻이다, 단지 5개의 레코드만 출력하기 때문일 것이다 또 다른 결과는 긴 테이블 이름 때
문에 발생한 숫자나 값의 오류가 생길 수도 있다 그러나 이런 사실들이 이 예제의 가치를 떨어뜨리지는 않는다 모두 여러
분의 데이 터를 훔치려고 하는 누군가에 의해 사용될 수 있을 것이기 때문이다
필자가 아는 대부분의 개발자들은 위의 예시를 보고, SQL injection에 대해 안전하다고 말할 것이 다.
왜냐하면 위 루틴에 입력하는값은세기 년 월 일 시간 분 초를 나타내는 8바이트바이너리 형태를
가진 오라콜 DATE 변수기 때문이다. 저 DATE 변수가 내 가 만들어 놓은 SQL 문을 변경할 수 있는 방
법은 없다고 생각한다. 뭐 곧 밝혀지겠지만 그들은 틀렸다. 이 코드는 변경될 수 있다. 방법만 안다면
쉽게 실행단계에서 수정될 수 있다(분명히 방법을 아는 사람들이 있다). 개발자들은 다음과 같이 위의 프
로시저가 실행될 것으로 기대할 것이다
ops$tkyte%ORA11GR2> exec inj( sysdate )
select *
from all users
빼ere created = '09.DEC.09'
PL/SOL procedure successfully completed.
이 결과는 SQL 문이 안전하게 구축되었다는 것을 보여준다. 그래서 어떻게 누군가가 이 루턴을 악의적
인 방법으로 시용할 수 있다는 것인가? 여러분이 이 프로젝트에서 악의적인 개발자와 같이 일하고 있
다고 가정해보자. 개발자들은 지금 데이터베이 스에 생성된 사용자를 보기 위해 이 프로시저를 실행할
권한을 갖고 있다고 하자. 그러나 그들은 이 프로시저를 소유하고 있는 스키 마 안의 다른 테이블에는
어떤 권한도 갖고 있지 않다. 심지어 이 스카마 안에 어떤 테이블이 있는지도 모른다. 보안팀이 권한을
24
• • • CHAPTER 01 성공적인 오라클 애플러케이션 개발
제한하는방법을시용한보안은훌륭하다. 보안팀은 어떤 사람도 테이 블의 이름을알수 없도록만들었
다. 그래서 아래와 같은 테이블이 존재한다는 것을 모르고 있다.
ops$tkyte%ORA11GR2> create table userJPw
2 (uname varchar2(30) p마mary key,
3 pw varchar2(30)
4 );
Table created.
ops$tkyte%ORA11GR2> insert into userJPw
2 (uname, pw )
3 values ( ’ TKYTE' , ’ TOP SECRET ' );
1 row created.
ops$tkyte웹RA11GR2> commit;
Commit complete.
pw 테이블은 매우 중요한 테이블처럼 보이지만, 시용지들은 이 테이블이 존재한다는 것조차 모른다.
그러나 그들은 INJ 루틴에 접근할 권한이 있다.
ops$tkyte웰RA11GR2> grant execute on inj to scott;
Grant succeeded.
따라서 악의적인 개발자/시용자는아래와같이 간단하게 실행할수 있다.
scott뼈RA11GR2> alter session set
2 nls date format = ’'"’ union select tname ,0,null from tab- -" ’;
Session altered.
scott%ORA11GR2> exec ops$tkyte. inj ( sysdate )
select *
from all user‘S
where created = ' ’union select tname ,0,null from
tab- -'
USER PN .... .
PL/SOL procedure successfully completed.
NLS_DATE_FORMAT은 흥미 로운 것이다. 대부분 사람들은 NLS_DATE]ORMAT으로 캐릭터 스
트링 문지를 시용할 수 있다는 것조차 모른다(휴~ 대부분의 사람들은 이런 ‘꼼수’를 사용하지 않고 데이터
포뱃을 바꿀 수 있다는 것조차 모르고 있다) 악의적인 사용자가 여기서 한 일은 여러분이 보호하는 테이블
25
전문가톨 위한 오라클 데이터베이스 아키텍처 • • •
을 여 러분의 권한을 사용하여 쿼리할 수 있도록 코드를 살짝 고치는 일이다 TAB 틱셔너리 뷰는 현재
스카마가 볼 수 있는 일련의 테 이블들만 볼 수 있도록 제 약이 있다. 사용자가 프로시저를 실행할 때 인
증을 위해 시용되는 현재의 스키 마가 그 프로시저의 소유자다(쉽게 말해 소유자는 당신이지 그들이 아니
다). 그들은 이제 스키 마 안에 어떤 테 이 블들이 있는지 볼 수 있게 되 었다. 그들은 USER]W 테 이블을
보고 “음, 흥미로운데”라고 중얼거릴지도 모른다. 그 다음에 그들은 그 태이블에 접속하려고 시도할 것
이다.
scott%ORA11GR2> select * from ops$tkyte .user-pwi
select * from Ops$tkyte.user-pw
*
ERROR at line 1:
ORA.ØØ942: table or view does not exist
악의적인 사용자는 테 이블에 직접 접근할 수는 없다. 그들에게는 해당 테이블에 대해 SELECT 권한이
없다. 그러 나 안티깝게도 테 이 블에 접근할 다른 방법이 존재한다. 사용지는 태 이 블에 있는 컬럼 에 관해
알고싶어할 때 아래와같이 테이블구조를 알수있는 방법이 있다.
scott%ORA11GR2> alter session set
2 nls_date_format "" 'union select tname : :cname ,Ø,null from col .. '" i
Session al tered.
scott%ORA11GR2> exec ops$tkyte.inj( sysdate )
select *
from all users
where created = " union select
tname 사 cname , Ø , null from col .. ’
USER 마VPN ..
USER 뻐JN매E .....
앞의 예 제 처럼 손쉽게 컬럼의 이 름을 알 수 있다. 스키 마 안에 있는 테 이블 이름들과 테 이 블의 컬럼 이
름을 알고 있 으므로, 되셔너리 테 이 블이 아닌 바로 u ser_pw 테 이블을 쿼리하기 위해 NLS_
DATE_FORMAT을 한 번 더 변경할 수 있다. 따라서 악의적인 사용지는 다음처럼 할 수 있다.
scott%O매11GR2> alter session set
2 nls_date_format = ’ 'union select uname ,Ø,null from user-pw .. ’” ;
Session altered.
scott%ORA11GR2> exec ops$tkyte.inj( sysdate )
select *
26
• • • CHAPTER 01 성공적인 오라클 애를리케이션 개발
from all users
where created = ' ’ union select uname ,0,null from
user yw-- ’
TKYTE_ .
PL/SOL procedure successfully completed.
scott%ORA11GR2> alter session set
2 nls date format = ’ " "union select pw, 0, null from user""pw -." , j
Sessìon altered.
scott%ORA11GR2> exec ops$tkyte_inj( sysdate )
select *
from all users
where created = ’ 'union select pW,0,null from
user yw- -'
TOP SECRET ...
PL /SOL procedure successfully completed.
위에서 처럼 악의적인 개 발자/ 시용자는 당신의 민감한 사용자명과 패스워드 정 보를 갖게 된다.
그렇다면 어떻게 여러분자신을 보호할것 인가? 아래의 예처 럼 바인드 변수를 시용하랴.
ops$tkyte%ORA11GR2> create or replace procedure NOT_inj( p_date in date )
2 as
3 1 Jec all_ users%rovπype;
4 c sysJefcursor;
5 l_query long;
6 begin
7 l_query := ’
8 select *
9 from all users
10 빼ere created = : x’;
11
12 dbms_output.put_line( l_query );
13 open c for l_query USING P_DATE;
14
15 for i in 1 . _ 5
16 loop
17 fetch c into 1 Jec ;
18 exit when c%notfound;
19 dbms_output.put_line( lJec.username 끼 ’ );
20 end loop;
21 close c;
27
전문가를 위한 오랴클 데이터베이스 아키텍처 • • •
22 end;
23 I
Procedure created.
ops$tkyte%ORA11GR2>
ops$tkyte없RA11GR2> exec NOT_inj(sysdate)
select *
from all users
where created = :x
PL/SOL procedure successfully completed.
바인드 변수를 사용하면 SQL injection 공격을 받지 않는다는 것은 쉽고도 단순한 사실이다. 바인드 변
수를 사용하지 않는다면 반드시 꼼꼼하게 코드 한 줄 한 줄을 조사해야 하고 (오리클의 소소한 것까지 다
알고 있는), 귀신처 럼 생각해야 하며, 공격을 받을 만한 곳이 없는가 살펴야 한다.99.9999% 의 코드가
SQL 벼ection에 노출되어 있지 않고 남아 있는 0.0001 % ( 이 것도 바인드 변수를 시용하지 않을 수도 있을
것이다) 에 대해서만 걱정 해야 한다면, SQL injection에 100% 노출되 어 있는 코드에 대해 걱정하는 것
보다훨씬 편하게 잠잘 수 있을것 같다
어쨌든 이 책의 시작 부분에 설명 한 그 프로젝트에서 바인드 변수를 사용하도록 기존 코드를 수정 할 수
있었는데, 그 결과 코드는 엄청 나게 빠르게 명령 들을 수행했고, 시스뱀에 감당할 수 있는 동시 접속자
의 수를 몇 배나 증가시킬 수 있었다. 더구나 코드는 더 안전해졌다. 전체 코드에서 SQL injection 이슈
들에 대해 검 토할 펼요가 없었다. 물론 이런 보안이라는 선물은 시간과 노력 이라는 큰 대가를 치르고
온 것이다. 고객은 시스템을 이미 개발한 이후 다시 뜸어 고쳐야만 했기 때문이다. 바인드 변수를 사용
하는 것은 오류를 유발할 만큼 어려운 일 이 아니다. 이건 순전히 처음부터 바인드 변수를 사용하지 않
았기 때문에 괜히 처음으로 돌아가서 모든 코드를 검토하고 변경하게 된 것뿐이 다. 개발자들。l 애플리
케이션을 만들 때 처음부터 바인드 변수의 사용이 중요하다는 것을 이해했다면 고객은 그러한 비용을
지불할 필요가 없었을 것이다
동시성 제어의 이해
‘동시 성 제어 (currency control)’ 는 데이터베이 스 자체를 구별하는 분야다. 또한 데이터베이 스를 파일
시스템과 구별하고, 데이터베이 스 간에 서로 구별하는 분야이 기도 하다. 프로그래머인 여러분이 접하
고 있는 데이터베이 스 애플리케이션이 동시 액세스 상황에서 정확히 동작하는 것 이 매우 중요하기도
하지만, 아쉽게도 반복적으로 태스트하지 못히는 것이기도 하다. 모든 사람이 동시 에 애플리케이션을
시용할 때 모든 이벤트가 동시에 발생하게 되면 조금 전까지만 해도 잘 동작하던 기술에서도 문제가
발생할수 있다(물론, 그속을살펴보면 반드시 잘수행되던 것은아니다). 여러분이 사용하고 있는 데이터베
28
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
이스가 동시성 제어를 어떻게 구현하고 있는지 잘 이해하지 못한다면, 필연적으로 아래와 같은 일틀을
겪게될것이다.
·데이터의무결성오류
• 사용자가 늘어가면서 점점 적은 수의 사용자들이 사용할 때보다 애플리케이션이 느려지는 현상
• 많은 수의 시용자들을 대응할 능력이 떨어지는 애플리 케이션
필자는 “아마도 ~할지 모른다” 또는 :할 위혐이 있다”고 말하지 않았다. 반드시 그런 상황을 겪게 될
것이기 때문이다. 심지어 이런 위험요소를 인식하지 못하면서도 일하는 경우가 수두룩하다. 올바른 동
시성 제어가 뒷받침되지 않으면 데이터베이스의 무결성을 깨뜨리는 일들이 발생할 수 있다. 개발자 스
스로 테스트할 때는 잘 작동하던 애플리케이션이 다중 사용자의 환경에서는 여러분이 기대하던 대로
작동하지 않을 것이기 때문이다 애플리 케이션은 데이터를 지연시간으로 인해 원래 설계했던 것보다
느리게 웅직일 것이다. 애플리케이션은 락과 경합의 문제들로 인해 확장성을 잃어벼릴 것이다 자원에
접속하는 큐가 더 길어질수록 대기 시간은 더욱 더 길어지게 된다.
차량이 발권이나 정산을 위해 대기 중인 도로 요금소를 비슷한 예로 들어보자. 자동차가 순서대로(예측
기능하게) 한 대씩 한 대씩 요금소에 도착한다면 요금소 앞에서 대기할 필요가 없다. 그런데 많은 자동
차들이 한꺼번에 도착하니 큐가쌓이기 시작하는 것이다. 게다가대기 시간은요금소에 서 있는자동차
의 숫자에 따라 선형적 (역자 주- 일차함수의 정비례)으로 증가하지 않는다. 어떤 지점을 넘어가변 상당히
많은 시간을 줄지어 기다리는 사람들을 ‘관리’ 하고 서비스하느라 더 많은 시간을 소모하게 된다(데이
터베이스 안에 있는 병렬 처리는 context switch를 갖고 있다).
동시성 문제는찾아내기 가장어려운문제다. 이 문제는멀티 쓰레드프로그램을디버깅하는것과비슷
하다. 프로그램은 디벼거의 제어될 수 있는 인위적인 환경에서는 잘 동작하지만, 실제 환경에서는 심각
하게 깨진다. 예를들어 두쓰레드가 경합중인 상황에서 두 개의 쓰레드는같은 데이터 구조를통시에
수정하면서 끝날 수 있다. 이런 종류의 버그는 찾기도 어렵고 수정하기도 어렵다 애플라케이션을 하
나만 띄어놓고 테스트한 후 많은 동시 사용자가 있는 환경에 설치하게 되면 미리 탐지하지 못했던 동
시성 문제들이 고통스러울 정도로 나올 것이다.
다음 두 절에 걸쳐 동시성 제어에 대한 정확한 지식이 없을 경우 어떻게 데이터를 손상시카고 성능과
확장성을 저해하는지 두 개의 작은 예를 통해 설명하겠다.
락킹 구현하기
데이터베이스는 특정 시간에 한 개의 트랜잭션이 하나의 주어진 데이터를 수정하는 것을 보장하기 위
해 락을 시용한다. 기본적으로 락은 동시성을 보장하는 메커니즘이다. 같은 로우에 대해 동시 업데이트
를 방지하는 락이 없다면 데이터베이스에 다중 사용자의 접근이 불가능할 것이다. 데이터베이스가 락
29
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
을 과도하게 사용하거나 부적절하게 사용한다면 동시에 트랜잭션을 수행할 수 있는 사람의 숫자가 제
한될 것이다 따라서 락이 무엇인지 데이터베이스 안에서 어떻게 동작하는지를 이해하는 것은 확장성
있는 정확한 애플리케이션을 개발하는 데 펼수적 이다.
필수적으로 각각의 데이터베이 스가 락을 서로 다른 방법으로 적용한다는 점을 이해하길 바란다. 어떤
데이터베이스는 페이지 레 벨 락킹을 하고 어떤 데이터베이스는 로우 례벨 락킹을 한다. 어떤 데이터베
이 스는 락을 로우 레벨에서 페이 지 레벨로 확장하고 어떤 데 이 터베이 스는 그렇게 하지 않는다 어떤
것은 락 읽기를 사용하고 어떤 것은 사용하지 않는다 어떤 것은 락을 이용해서 트랜잭션을 직렬화하
고, 어 떤 것은 락이 없이 데이터의 ‘읽 기 일관성 뷰 (read-consistent view)' 를 사용해서 락과 같은 방식
을구현한다. 이런 크고작은차이점들은큰 성능이슈나어처구니 없는버그를발생시킬수있다. 이런
결과는 락이 어떻게 작동하는지 이해해야 하는 펼수 이유기도 하다
오라클의 락 정책을 요약해보자.
• 오라클은 데이터 를 수정할 때 로우 례벨 락을 시용한다. 블록이나 테이블 레 벨로 락이 확장하는 경
우는없다
• 오라클은 데이 터를 단순히 읽을 때는 락을 시용하지 않는다. 즉 단순히 데이터 를 읽을 때는 데이
터의 로우에 락을걸지 않는다는것이다.
• 데이터 쓰기 작업은 데이터 읽기 작업을 가로막지 않는다. 반복해서 말하지만, “읽기 작업은 쓰기
작업으로부터 방해받지 않는다” 오리클이 읽기가 쓰기에 의해 락이 걸리는 많은 다른 데이터베이
스와 다른 근본적인 차이점이다. 물론 이 개념이 매우 좋은 속성 인 것처럼 들리겠지만, 사용자가
이 개념을 완벽하게 이해하지 않고 애플리케이션 로직을 통해 애플리케이션 안에서 무결성 제약을
수행하려고 한다면 잘못될 가능성이 크다.
• 데이터 쓰기는 오직 이미 락이 걸린 로우에 대 하여 또 다른 쓰기 를 실행하려 할 때에만 차단한다
데이터를 읽는 세션은 데이터 를 쓰는 세션을 블로킹하거나 제어하지 않는다.
여러분은 이러한 요소들을 고려해서 애플리케이션을 개 발해야 하며 이런 정책은 오리클만의 유일한
정책인 것 또한 이해해야 한다. 모든 데이터베이 스는 락 정책 에 있어서 미묘한 차이점 들을 가지고 있
다. 애플리케이션을 개발할 때 가장 기본적인 공통 기능을 사용해서 개발하더라도, 각각의 데이터베이
스들이 채택하고 있는 락과 동시 성 제어 모댈틀은 서로 다를 것 이다. 사용하고 있는 데이터베이 스가 어
떤 종류의 동시성 문제 제어 방법을 구현하고 있는지 이해하지 못한 개발자는 분명히 데이터 무결성 문
제로 인한 심각한 오류에 직면하게 될 것이다(이런 것들은 주로 다른 데이터베이스를 오라클로 이식하거나
그 반대 의 작업을 할 때 애플 리케이션 안에 있는 동시성 메커니즘의 차이점을 무시하기 때문에 발생한다).
30
• • • CHAPTER 01 성공적인 오라클 애플러케이션 개발
Lost updates 방지하기
오라클의 non-blocking 접근법의 부작용 중 하나는 한 번에 한 로우의 데이터에 한 명 이상의 사용자
가 접근하지 않도록 하기 위해서 락 이외에 추가적으로 해주어 야 할 일 이 있다는 것이다.
어떤 개발자가 회의실 및 프로젝터 등의 자원 스케줄링 프로그램을 시연했다. 방금 개 발을 마치고 실제
운영을 위해 설 치 중에 있는 프로그램이었다. 이 애플리케이션은 주어진 시간 동안 한 명 이상의 사람
에게 자원을 할당하지 않도록 하는 비 즈니 스 규칙을 적용했다 즉 그 애플리케이션은 이미 다른 사람
이 여l 의댄f 시간대를 검사히는 코드를 포함하고 있었다(적어도 개발자는 그렇게 생각했다). 이 코드는 스케
줄 테이블을 조회하여 원하는 시간대에 중복된 데이터 가 없으면 새로운 데이터를 입력하였다. 개발자
는 기본적으로 두 개의 테이블을 사용했다.
ops$tkyte%ORA11GR2> create table resources
2 (resource_name varchar2(25) primary key,
3 other data varchar2(25)
4 );
Table created.
ops$tkyte%ORA11GR2> create table schedules
2 (resource_name varchar2(25) references resources,
3 start_ time date,
4 end time date
5 );
Table created.
SCHEDULES 테이블에 방 예약 데이터를 입력하고 커맛을 하기 전에 애플리 케이션은 아래 처럼 쿼리
할수도있을것이 다.
무척 간단해서 더 는 수정할 필요가 없었다 (적어도 개발자에게는 그랬다) 숫자가 1 이 나오면 그 방은 당신
것이 된다 만일 1 보다 큰 숫자가 나온다면 필요한 그 시간대에는 방을 예의빨 수가 없다. 이 로직을 보
자마자 펼자는 아주 간단한 테스트를 통해 이 애플리케이션에서 발생할 수 있는 오류를 보여주었다 어
쩌면 이런 종류의 오류는 발견하기 매 우 어렵고 분석하기 어려웠을 것이 다. 이런 오류를 마치 데이터베
이 스가 가지고 있는 버 그라고 생각할지도 모르겠다
31
전문가를 위한 오라클 데이터베이스 아키텍처 .. . .
필자는 다른 사람이 개발자의 옆 에서 다른 창을 열어놓고 그것을 사용하도록 했다. 두 명은 같은 화면
을 열고, 셋을셀 때 동시에 Go 버튼을클력하여 동시에 같은방을예약하도록 시도했다. 두 명 다동일
시간대에 예약이 되었다 이 로직은 한 명만 접속해서 수행할 땐 완벽했지만 다중 사용자의 환경에서
는 실패하고 만 것이다. 이런 문제는 오라클의 non-blocking 읽기 때문에 발생한다. 어떤 세션도 다른
세션에 락을 걸지 않는다 두 개의 세션은 단순히 쿼리를 수행했고 방을 예약하도록 로직을 수행했다
둘 다 예약현황을 찾는 쿼리를 수행했다. 심지어 다른 세션은 이미 SCHEDULES 테이 블을 수정하는
작업을 시작한 상태이기도 했다(커맛이 일어나기 전에는 다른 세션에는 변경된 상황이 보이지 않는다 이때는
이미 너무 늦었다). 그것들은 SCHEDULES 테이블 안에 있는 같은 데이터 를 수정하지는 않았기 때문에
절 대 서로 블로킹을 걸지 않았고 비즈니스 룰(역자 주 동일 시간대에 하나의 방은 한 영 이상의 사용자가 예
약할 수 없대은 원래 의도된 대로 지켜질 수가 없었다.
개 발자에게는 다중 사용자 환경에서 비 즈니스 룰을 강제할 수 있는 방법이 필요했다. 주어진 자원에 대
해 한번에 정확히 한명만예약할수 있도록하는방법이 필요했다. 이런 경우의 해 결 방법은쿼리 자
체 에 약간의 직렬화 기능을 부여하는 것이 다. 앞의 count(*)를 수행하는 것에 덧붙여서, 개발자는 먼저
다음의 쿼리를수행했다.
select * from resources where resource_name = :resource_name FOR UPDATE;
여기서 해야 할 일은 자원(방)을 스케줄링 하기 전에 그것에 락을 거는 것이다. 즉, 해당 자원에 대해
SCHEDULES 테이블을 쿼리하기 전에 락을 거는 것이다 스케줄을 선점하려는 자원에 락을 걸 어둠으
로써 다른 사용자가 이 자원을 동시 에 수정 하지 못하도록 보장할 수 있다. 모든 사람은 스케줄 데이터
를 볼 수 있는 시점인 트랜잭션 커맛을 완료할 때까지 기다려야 한다. 이렇게 하면 중복 예약에 대한 위
험 이사라진다.
개발자들은 멸티 시용자 환경 에 서 때로 멀티 쓰레드 프로그램에서 사용된 것과 비슷한 기술을 사용해
야 한다는 것을 이해해야 한다 FOR UPDATE 절은 이 경우에 세마포어와 유사한 역할을 수행한다.
그것은 두 명의 사람이 동시에 그것을 스케줄할 수 없도록 보장함으로써 RESOURCE 테이블의 특정
한 데이터에 대한 접근을 순차적으로 처리하도록 한다.
FOR UPDATE 접근법을 사용하더라도 예약 가능한 자원이 수전 개나 있기 때문에 동시 처리는 여전
히 가능하다. 우리가 한 일은 단지 한 사람만 동시에 한 가지 자원을 수정할 수 있도록 보장하는 것이
다. 물론, 우리가 실제로 갱신하려는 데이터에 대해 수동으로 락을 거는 경우는 매우 드물게 발생한다
여러분은 어디서 수동으로 락을 걸 어야 할지 알아야 한다. 또한 어디서 수동으로 락을 걸어야 할지 아
는 것과 동일한 중요도로 언제 락을 걸거 나 혹은 말아야 하는지 이해할 필요가 있다(이 부분에 대해 작은
예를 제시해볼예정이다) 물론 FOR UPDATE 절은다른 데이터베이 스들처 럼 다른사람이 데이터 를 읽
32
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
는 때에는 자원에 대해 락을 걸지 않는다. 따라서 이 방법은 매우 확장성이 있을 것이다.
이번 절에서 설 명한 이슈들은 이기 종 데이터베이스 간에 애플리케이 션을 이식하려 할 때 많은 영호t을
미친다(다른 장에서 이 주제에 대해 다시 디룰 것이다). 이 이슈들은 사람들을 계속해서 걸려 넘어지게 하는
것 이다. 예를 들어 여러분이 쓰기가 읽기 에 락을 걸거나 읽기가 쓰기에 락을 거는 기 능을 가진 다른 데
이터베이 스들에 익숙하다면 여러분은 데이터 무결성 문제에 대해서는 편할 수도 있다 동시성이 없다
는 것은 여러분 자신을 이런 문제에서 보호하는 한 가지 방법이 되며 오라클이 아닌 다른 많은 데이터
베이 스가 작동하는 방법이기도 하다 오라클에서 동시성은 중요하게 다루어져야 할 룰이며, 반드시 이
부분을 중요하게 인식하고 있어야한다 결괴들은 다르게 발생할 것이며 중요한부분에 대해 어려움을
겪기도할것이다
필자는 이 런 종류의 예제를 보여준 후에도 여전히 동시성 제어와 같은 부분을 잘 이해해야 한다는 점
을 무시하는 개발자들이 우글대는 곳에서 세 션 설계를 해왔다. 이 런 종류의 개발}들은 한결같이 “우
리는 하이버네이트 애플리케 이션 안에 있는 ‘σansactional’ 기능 박스를 제크했고, 하이 버네이 트가
모든 트랜잭션을 관리하고 있기 때문에 그 내용을 굳이 알 필요가 없어요”라고 말하는 것이다. “그렇다
면 하이버네이트가 SQL 서버와 DB2와 오라클에 대하여 각각 완전히 다른 코드를 생성하고, SQL 문
만큼 다른 로직도 생성합니까?"라는 필자의 물음에 그들은 아니라 말했지만 실제로는 트랜잭션을 관
리한다고 했다. 이것은 중요한 핵심을 놓친 것이 다. 이런 상황에서 트랜잭션 처리를 한다는 것은 단순
히 커빗과 롤백을 지원한다는 의미일 뿐 생성된 코드가 일관성 있는 트랜잭션을 한다는 의 미가 아니다
(코드가틀리다는것이다) . 데이터베이스에 접근하기 위해 시용되는툴이나프레임워크와상관없이, 여러
분이 데이터 를 손상시키지 않으려면 동시성 제어에 대한 지식은 필수인 것 이다.
전체 시 간의 99% 동안 락킹은 완전히 투명하게 관리되기 때문에 여 러분이 직접 관여할 필요가 없어야
한다. 나머지 1 % 의 시간을 이 를 인식하기 위해 훈련하는 데 사용해야 한다. 이런 이슈에 대해서 아쉽
게도 ‘이 일을 한다면 이러이러한 일을 해야 한다’ 는 간단한 체크리스트는 없다. 성공적인 동시성 제어
는 여러분이 만든 애플리 케이션이 다중 사용자 환경에서 어떻게 동작할 것인지, 데이터베이 스 내부에
서는 어떻게 동작할 것인지의 이해에 달렸다.
여러분은 항상 각별한 관심을 기울여야 하기 때문에 대부분은 수동 락킹이나 또는 다중 사용자 환경에
서 무결성을 보장하기 위한 다른 기술에 의지해야 할 경우에 대해 이야기 할 것 이다. 한 개 또는 두 개나
그 이상의 태이블에서 유지해야 할 비즈니 스 규칙(혹은 데이터 규칙 )이 한 테이블 여러 로우 혹은 (참조
무결성 같이) 여러 테이블 로우에 걸쳐 있는 경우일 젓이다.
멀티벼저닝
‘멀티버저닝 (multi-versioning)’은 오라클의 동시성 제어 메커니즘의 기초를 형성하는 통시성 제어와
33
전문가를 위한 오라클 데이터베이스 아키텍처 • •
아주 밀집한 관계가 있는 주제다 오라클은 다중 버전 읽기 일관성 모댈을 기본으로 제공하는 기능이
다 7장 ‘동시성과 멀티버저닝’ 에서 자세히 디룰 예정이다.
• 읽기 일관성 쿼리 각시점별로 일관된 결과를추출한다 .
• NON-8LOCKING 쿼리 - 다른 데이터베이스와는 탈리 읽기 처리는 쓰기 처리에 의해 절대 블로
킹되지 않는다.
이것은 오라클 데이터베이스의 핵심 개념이다. 멀티버저닝이라는 용어는 기본적으로 데이터베이스 내
부에 있는 여러 버전의 데이터를 동시에 관리할 수 있는 오라클의 기능(1 983 년 3.0 버전부터 지원)이며,
‘읽기 일관성 (read-consistency )’ 이라는 용어는 오리클의 쿼리는 어떤 시간의 일관된 지점에 있는 결과
를 반드시 보존한다는 돗이다. 쿼리에서 조회에 사용되는 모든 블록은 쿼리를 수행하는 동안 누군가가
수정하거나 락을 걸더라도, 정확승1 사용자가 조회한 시 점의 값을 유지한다. 여러분이 멀티버저닝과 읽
기 일관성과 같이 동작한다는 것을 이해했다변 데이터베이스에서 얻을 수 있는 결과를 항상 이해할 것
이다. 이 부분을 좀 더 자세히 알아보기 전에, 오라클의 멀티벼저닝을 보여주기 위한 간단한 예부터 살
펴보자.
34
ops$tkyte예RA11GR2> create table t
2 as
3 select *
4 from all users
5 /
Table created.
ops$tkyte%ORA11GR2> set autoprint off
ops$tkyte%ORA11GR2> variable x refcursor;
ops$tkyte%ORA11GR2> begin
2 open :x for select * from t;
3 end;
4 /
PL/SQL procedure successfully completed.
Ops$tkyte%ORA11GR2> declare
2 pragma autonomous_transactionj
3 •• you could do this in another
4 •. sqlplus session as well, the
5 •• effect would be identical
6 begin
7 delete from t;
8 commit ;
9 end;
10 /
PL/SQL procedure successfully completed.
ops$tkyte%ORA11GR2> print x
USER뻐ME
B
A
OPS$TKYTE
OUTLN
SYSTEM
SYS
40 rows selected_
• • • CHAPTER 01 성공적인 오라클 애툴리케이션 개발
USER 10 CREATED
102 07-oct-2009 08:26am
101 07-oct-2009 08 :26am
191 09-dec-2009 01:20뻐
9 13-aug-2009 11 :01pm
5 13-aug-2009 11 :00pm
o 13-aug-2009 11:00pm
이 예제에서 T라는 테스트 테이블을 생성하고 ALL_USERS 태이블에서 몇몇 데이터 를 가져와 저장하
였다. 우리는 이 테이블에 대해 커서를 오픈했다. 커서로부터 아무런 데이터도 패치하지 않았고 단지
열어놓은상태를유지했다
I Note I 오라클은 그 쿼리에 ‘응답’ 하지 않는다는 것을 영심하라 커서를 오푼했다고 해서 데이터베이스의 데이터를 일는
다는 보장은 없다 10억 건이나 되는 테이블에서 커서를 오푼할 때 데이터를 바로 가져온다면 엄청나게 오랜 시간이 걸리지
않겠는가? 커서는 순식간에 오푼하고 쿼리가 진행될 때 응답할 뿐이다‘ 다시 말해서 커서는 매치할 때 테이블에서 데이터를
읽어들인다
같은 세션(또는 다른 세션에서도 이것처럼 움직일 것이다)에서 테이블의 모든 데이터 를 지웠다. 지우고 난
후 커빗까지 했다. 데이터들은 모두 사라졌다. 어디로 간 것일까? 사실 사라진 데이터 들은 커서를 통
해 다시 뽑아낼 수 있다 OPEN 명령어의 결과로추출할수 있는 결과집합은우리가 커서를오픈한시
점에 미리 예정된 것이다. 오픈후에는 테이블블록을 전혀 손댈 수가 없기 때문에 결과는돌처럼 굳어
진다. 패치하기 전에는 어떤 응답이 올지 알 방법이 없다. 그러나 결과는 커서의 관점에서 보면 변경할
수 없는 것 이다. 오라클은 커서를 오픈할 때 어떤 다른 영역에 있는 데이터 를 카피하지 않는다. ‘언두
혹은 롤백 세그먼트 (undo or rollback segment)’ 라고 부르는 영역에 데이터 를 저장하는 것은 사실
DELETE 명 령뿐이다.
플래시백
과거 오라클은 항상 쿼리 결과가 일관되도록 특별한 하나의 시점을 결 정하였다. 그리고 이런 결정은 오
픈된모든결과집합이 최신의 데이터임을보증하였는데 다음두가지 시점 중하나가적용된다.
• 쿼리가 오푼된 시점 - 이것은 READ COMMITTED isolation의 기본적인 동작이다 (7장에서
READ C01-1MITIED, READ ONLY, 그리고 SERIALIZABLE 트랜잭션 레벨 사이의 차이점들을 다롤 것
35
전문가를 위한 오라클 데이터베이스 아키택처 • • •
이다).
• 쿼리가 속해 있는 트랜잭션이 시작되는 시점 이것은 READONLY와 SERIALIZABLE의 레벨
의 기본동작이다.
그런데 오리클 9i부터 나온 플래시백 쿼리 기능은 ‘as of’ 절을 통해서 과거 특정 시점 기준으로 쿼리 를
실행할 수 있게 한다. 이 기능으로 읽기 일관성과 멀티버저닝을 좀 더 자세히 살펴보고 시연할 수 있다.
I Note I 여러 달 또는 수년 전의 데이터를 조회하는 플래시백 쿼리에 사용되고, 오라클 11g 렬리즈 1 또는 그 상위 버전에
서 사용 가능한 플래시백 데이터 아카01브는 특정 시점의 데이터베이스 내부에 있는 데이터를 생산하기 위해 읽기 일관성과
멀티버저닝을 사용하지 않는다. 대신 아카이브 속에 들어 있는 자료의 이전 이미지 복사본을 사용한다 우리는 플래시백 데
이터 아카이브에 대해서는 뒤의 장에서 다룰 것이다.
다음 예제를 보자. 우리는 SCN (System Change 또는 System Commit number 둘 다 사용할 수 있는 용어
다)을 얻으려고 한다 SCN은 오라클의 내부에서 동작하는 시계와 같은 것으로 커맛이 발생할 때마다
이 시계는 증가된다. 우리는 date 또는 timestamp도 사용할 수 있지만 SCN은 쉽게 사용 가능하고 매
우정확하다.
scott%ORA 11 GR2> var‘ iable scn number
scott%ORA11GR2> exec :scn := dbms_flashback.get_system_change_number;
PL/SQL procedure successfully completed.
scott%ORA11GR2> print scn
SCN
6294346
I Note I DBMS_FLASHBACK 때키지는 여러분의 시스템에서는 권한이 제한되어 있을 수도 있으며, 시언을 위해 때키지에
대한 사용 권한을 scon 사용자에게 주었다 여러분도 똑같이 따라해주길 바란다
아래의 쿼리 결과를통해 SCN을 얻었고 오라클이 우리가쿼리할 시점을 알려줄수 있도록하였다. 우
리 는 오라클을 나중에 쿼리하고 우리가 원하는 정확한 시 점 에 데이터가 테이블에 있는 것을 보고 싶
다. 우선은 EMP 태이블에 있는 내용을 조회해보자
scott%ORA11GR2> select count(*) from emp;
36
I
. . .. CHAPTEROl 성공적인 오라클 애플리케이션 개발
COUNT(*)
14
이제 태이 블의 모든 데이터 를 삭제하겠다.
scott%ORA11GR2> delete from emp î
14 rows deleted.
scott%ORA11GR2> select count(*) from emp;
COUNT(*)
@
그러 나 ASOF SCN 또는 AS OF TIMESTAMP 등의 플래시백 쿼 리를 사용하면, 특별한 시 점 의 테이
블에 있는 내용을 추출할 수 있다.
scott%ORA11GR2> select count(*) ,
2 :scn then_scn,
3 dbms_flashback.get_system_change_number no만scn
4 from emp as of scn : scn î
COUNT (*) THEN SCN N(뻐 SCN
14 6294536 6294537
더 나아가 이 런 기 능은 트랜잭 션의 경 계에 걸 쳐서도 동작한다 심 지어 같은 쿼 리 로 서로 다른 두 시점
의 데이터를조회할수도있다. 매우 흥미 롭지 않은가?
scott%ORA11GR2> commit;
Commit complete.
scott%ORA11GR2> select cnt_now, cnt_then,
2 :scn then_scn,
3 dbms_flashback.get_system_change_number now_scn
4 from (select count(*) cnt_now from emp) ,
5 (select count(*) cnt_then from emp as of scn :scn)
6 /
CNT NC빼 CNT THEN THEN SCN NOW SC깨
37
전문가를 위한 오라클 데이터베이스 아키텍처 ‘ . .
o 14 6294536 6294539
결론적으로, 여 러분이 오리클 lOg 이상을 시용하고 있다면 멀티벼저닝 기술을 사용하는 ‘플래시백
(flashback)’ 이 라고 불리는 명령어를 사용할 수 있다. 이 명령 어 는 여러분이 원하는 이 전 시점의 상태를
볼 수 있도록 해줄 것이며 이 경우 EMP 테 이블을 모든 정 보를 삭제하기 이전 시점으로 되돌릴 수 있
게 된다.
scott%ORA11GR2> flashback table emp to scn :scn;
Flashback complete.
scott%ORA11GR2> select cnt_now, cnt_then,
2 :scn then_scn,
3 dbms_flashback. get_system_change_number now_scn
4 from (select count(*) cnt_now from emp) ,
5 (select count(*) cnt_then from emp as of scn :scn)
6 I
C깨T NOW CNT THEN THEN SCN NαN SC깨
14 14 6294536 6294552
읽기 일관성 과 멀티버저닝 에 대해 설명하였다. 만일 아직까지 여러분이 오라클의 멀티 버 저닝 스키마가
어떻게 동작하고, 어 떤 의 미 를함축하고 있는지 이해하지 못했다면, 오라클의 충분한장점을활용하지
못할 것이며, 데이 터 무결성을 보장하는 오라클 애플리케이션을 제대로 작성하지 못할 것이다.
읽기 일관성과 non-blocking 읽기
멀티벼저닝, 읽기 일관성 쿼리들과 non-blocking 읽기의 의미를 조금 더 살펴보자. 멀티버저닝에 익숙
하지 않다면, 다음에 있는 코드가 그저 놀라울 것이다. 조회 대상 테이블은 한 개의 데 이터 베 이스 블록
(데이터베이스의 저장 최소 단위)마다 한 개의 로우를 저장한다고 가정해보자. 그리고 이 예제 에서와 같이
전체 테이블을 스캔해보도록 하겠다.
우리가 쿼리할 테 이블은 간단한 ACCOUNTS 테 이블이 다. 이것은 매우 단순한 구조를 갖고 있는 은행
계좌의 잔고를 보관하는 테이블이다.
38
create table accounts
( account_number number primary key,
account balance number
• • • CHAPTER 01 성공적인 오라클 애을리케이션 개발
실제 ACCOUNTS 테이블은 수십만 개의 로우를 갖고 있을 것이다. 간단히 하기 위해서 표 1-1 에서 보
여주는 것처럼 4개의 로우만 가지고 진행하고 있다 (7장 ‘동시성과 멀 티버저닝’ 에서 다시 다룰 것이다).
표 1-1 I Accounts 테이블 내용
I홉.같i설률품킬 i!일흩밸과
2
3
4
123
234
345
456
$500.00
$250.00
$400.00
$100.00
여기서 은행 잔고를 보여주는 일마감 리포트를 실행하고자 하면 다음과 같은 아주 간단한 쿼라면 충분
하다.
select sum(account_balance) from accountsi
물론, 이 예제에서 답은 명확하게 $1250 0 1 다. 그러나 로우 2와 로우 3을 읽고 있는 동안 ATM에서 누
군가가 이 테이블에 트랜잭션을 발생시키고 계좌 123에서 계좌 456로 $400을 이체시카고 있다고 가정
하면, 로우 1을 읽을 때 무슨 일이 발생하겠는가? 쿼리는 로우 4에서 $500을 계산하고, $1 , 650을 응답
한다. 물론, 이것은 피해야 할 오류다. 이런 금액은 잔고 컬럼에 결코 존재한 일이 없다. 오라클은 이런
오류를 피하기 위해 읽기 일관성 방법을 사용한다. 오라클의 방식은 다른 대부분의 데이터베이스들의
방식과달라충분히 이해해야할필요가있다.
다른 많은 데이터베이스에서 이 쿼리에 대해 일관적이고 정확한 결괴를 얻으려면, 합계를 계산하는 기
간 동안 전체 테이블에 락을 걸고 읽거나 읽고 있는 여러 로우에 대해 락을 걸고 있어야 한다. 이 락이
여러분이 값을 읽는 동안 다른 사람이 값을 변경하는 것을 방지한다. 테이블에 락을 건다면 쿼리가 시
작되는 시점에 데이터베이스에 있는 값을 응답받는다. 데이터를 읽을 때 데이터에 락을 건다면 쿼리가
종료되는시점에 실제 데이터베이스에 있는값을응답받는다. 일반적으로공유 읽기 락이라하는데, 이
것은 여러분이 응답을 얻는 동안에 다른 사람이 값을 변경하는 것을 방지하는 방식이다. 이렇듯이 테이
블 락은 여러분이 쿼리 히는 동안 전체 터l 이블에 발생할지도 모르는 갱신을 방지한다. 위의 예처럼 4 개
의 로우만 가진 태이블에 대해서는 짧은 순간에 처리를 하겠지만 수백만 건의 로우를 가진 테이블에
대해서는 몇 분의 시간이 걸릴 수도 있다. 처리하는 데이터마다 락을 거는 방식은 여러분이 읽고 처리
중인 데이터에 대해 갱신을 방지하겠지만 실제로는 쿼리와 여러 갱신 처리 를 할 때 데드락을 발생시킨

필자는 암서 멀티벼저닝의 개념을 이해하지 못했다면 오라클의 장점을 완전히 활용할 수 없다고 말했
39
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
다. 그 이유 한 가지를 설명해보면 오라클은 쿼리가 시작하는 시점에 존재하는 데이터 의 응답을 하기
위해 멸티 벼저닝을 사용한다. 쿼리는 어떤 것에도 락을 걸지 않고 수행한다. 계좌가 로우 1 에 서 4로 이
체되는 트랜잭션을 수행하는 동안, 이 로우들은 쓰기 작업에 대해서는 락이 걸리지만 SELECT SUM
.. 쿼리 등과 같은 읽기 작업에 대해서는 어떤 락도 걸지 않는다. 사실 오라클은 다른 데이터베이스에
서 일반적인 락 유형인 ‘'shared read' 락이 없다. 오라클은 그것을 필요로 하지 않는다. 동시성 작업을
방해하는것중제거될수있는것은모두제거되어 있다.
필자는 오랴클의 멀티벼저닝을 이해하지 못한 개발자가 개발한 리포트가 전제 시스템에 완전히 락을
걸어버린 경우를 엄청 나게 자주 목격했다. 이유는 간단했다 개발자들은 쿼리들을 작성하면서 읽기 일
관성이 유지된 결과, 즉 정확한 결과물을 얻기 원한다. 다른 데이터베이스들에서 이런 작업을 할 때 개
발지들은 테이블 전체에 락을 걸기도 하고, 특히 SQL 서버에서는 공유 모드를 사용하여 로우를 락하는
데 필요한 메커니 즘인 SELECT ... WITH HOLDLOCK을 시용했다. 그래서 개발자들은 리포트 작업
을 수행하기 에 앞서 테이블에 락을 걸거 나 자기 생각에는 WITH HOLDLOCK과 비슷하다고 생각한
SELECT .... FOR UPDATE를 사용한다 이렇게 하면 시스템이 정상적으로 트랜잭션을 처리할 수 없
게된다
그렇다면 오라클은 어떤 데이터에도 락을 결지 않고 동시성을 감소시커지 않으면서 어떻게 $1 , 250이라
는 정확한 결괴를 얻을 것인가? 오리를이 사용하는 트랙잭션 메커니즘에 비밀의 열석가 있다 여러분
이 데이터 를 수정할 때마다 오라클은 두 개의 다른 위치에 엔트리를 만든다(다른 데이터베이스들은 대부
분 두 개의 엔트리를 같은 위치에 놓을 것이다. 그것들에게 언두 (undo)와 리두 (red이는 단지 트랜잭션 데이터일
뿐이다) 한 개의 엔트리는 오라클이 리두나 트랜잭션을 롤백을 하기 충분한 정보를 저장하는 정보를 저
장하는 리두 로그에 있다. 입력에 대해서 이것은 아마도 입력된 로우일 것 이다 삭제에 대해서는 파일
X, 블록 Y, 로우 슬롯 Z에 있는 로우를 삭제하라는 메시 지 등이다. 또 다른 엔트리는 언두 엔트리로 언
두 세그먼트에 쓰여진다 만일 트랜잭션이 실패하여 원상태로 되돌릴 필요가 있다면, 오라클은 언두 세
그먼트로부터 ‘이전’ 의 이미지를 읽고 데이터를 복구할 것이다. 언두 트랜잭션에 언두 세그먼트를 사
용하는 것 외에도, 오라클은 블록들을 읽을 때도 쿼리가 시작하는 시점의 블록을 복구하기 위해 블록의
변경상황을 언두하기 위해 언두 세그먼트를 시용한다.
따라서 위의 예제에 관련되어 오리클은 표 1-2 에 설명한 대 로 처리를 한다.
40
• • • CHAPTER 01 성공적인 오라클 애를리케이션 개발
표 1-2 I 멀티버저닝 예제
시간 쿼리 져|확 변경 트랜잭션
T1 로우 1 읽는다 잔액 =$500; 현재 합계 =$500
T2 로우 1 업데이트, 다른 업데이트를 하지 않도록(읽기는
상관없음) 로우 1 에 배타적인(전용의) 락을 건다, 로우
1 은 $100을 가진다
T3 로우 1 읽는다 잔액 =$250; 현재 합계 =$750
T4 로우 3 읽는다 잔액 =$400; 현재 합계 =$ 1150
T5 로우 4 업데이트, 다른 업데이트를 하지 않도록(읽기
는 상관없음) 블록 4에 배타적인(전용의) 략을 건다
로우 4는 $500을 가진다
T6 로우 4 읽는다, 로우 4가 수정됐다는 것을 발건
한다 T1 시점에 보였던 것처럼 보이기 위해 블
록을 실제 롤백할 것이다 이 블록에서 $100 값
을읽을것이다
T7 트랜잭션 커맛
T8 $1250을 결과로 보여준다
T6 시점에서 오리를은 트랜잭션이 로우 4 에 실행한 락을 효과적으로 읽는다. 이것은 어떻게 nonblocking
읽기가 실행되는지 보여주는 좋은 예다. 오라클은 단지 데이터가 변경되었는가만 찾을 뿐이
며, 데이터가 현재 락이 걸려 있는지 변경되고 있는지는 상관하지 않는다. 오리클은 언두 세그먼트에서
과거 값을추출하고다음블록의 데이터로진행한다.
이것은 멀티벼저닝의 또 다른 예라 할 수 있다. 오라클에서는 각기 다른 시점에 있는 같은 정보의 멸티
버저닝을 사용할 수 있다. 오라클은 읽기 일관성 쿼리와 non-blocking reads를 할 때 각각 다른 시점
에 데이터를보여주기 위해 해당스댐삿을 이용할수 있다
이런 읽기 일관성 데이터는 항상 SQL 문 레벨에서 수행된다. 어떤 SQL 문의 결과라도 그것이 시작한
시점에 관련되어 올바른 데이터를 보여줄 것이다. 이러한 방식은 그 후 발생하는 INSERT와 같은 구문
을 예측 기능하게 만드는 것이다
for x in (select * from t)
loop
insert into t values (x.username, x.user_id, x.created);
end loop;
SELECT * FROM T의 결과는 쿼리가 실행을 시작할 때 미리 정해진다 SELECT는 INSERT에 의해
41
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
생성된 새로운 데이터를 어떤 것도 보지 못한다. 그렇 지 않다면 이 문장은 아마도 무한 루프가 될 것이
다. 만일 T 태이 블 안에 INSERT 구문이 새로운 로우를 생성할 때 SELECT가 새로 입력된 로우를 볼
수 있다면, 앞에 있는 코드는 로우의 개수를 알 수 없게 된다. 테이 블 T가 10 개 의 로우로 시작했다면,
20, 21 , 23 또는 명확하지 않은 숫자로 끝나게 될 것이다. 이것은 완전히 예측 불기능한 일이다. 읽기
일관성은 모든 구문에 적용되는 것이어서 다음의 INSERT 구문도 그 결과가 예측 가능하다.
insert into t select * from t;
INSERT 문 안에서는 테이 블 T에 대한 읽 기 일관성 뷰가 제공된다. 그것은 방금 입력한 로우를 볼 수
없을 것 이 다. 오히려 SELECT가 시작될 시점에 존재한 로우를 입력할 뿐이 다. 몇몇 데이터베이스는 실
제 몇 개의 로우기- 입력 되었는지 알 수 없기 때문에 위의 예와 같은 재귀 적 인 문장은 아예 허용조차 하
지 않을것이다.
따라서 여러분이 쿼리 일관성과 동시 성에 관련해서 다른 데이터베이 스로 작업하는 것 에 익숙하거나 저
런 개 념 에 대해 고민해본 적이 없다면(즉 데이터베이스 실무 경험이 없다면) 이제는 이 개념 을 이해하는
것이 여러분에게 얼마나 중요한 것인지 알 수 있었을 것이다. 오라클의 능력을 극대화하고 정확한 코드
를 구현하기 위해서 , 다른 데이터베이 스에 어떻게 되어 있는지가 아니라 오라클에 존재하는 이러한 이
슈에 대해 이해해야 할 것이다.
데이터베이스 독립성 (비의존성)
이제 이 절 에서 다루려는 내용을 충분히 이해할 것이 다 위 내용에서 오라클이 다른 데이터베이 스와는
어떤 특징들이 서 로 다르게 구현되어 있는지 언급했다. 간단한 읽기 전용 애플리케이션을 제외하고, 매
우 확장성이 높은 데이터베이 스 독립적인 애플리 케이션을 구축하는 것은 매우 어 렵다. 이런 주장은 각
각의 데이터베이 스가 어떻게 작동하는지 세세한 부분까지 자세하고 정확히 알고 있지 않으면 불가능한
일 이다. 그리고 여러분이 각각의 데이터베이 스를 자세하게 알고 있다면 데이터베이 스 독립성은 여러
분이 이루려고 하는 일이 아니라는 것을 알게 될 것 이다. 물론 끝없는 논쟁거 리기 도 하다.
간단한 시연을 위해 FOR UPDATE 절을 덧붙였던 자원 스케줄 샘플의 처음 버 전을 다시 생각해보자.
이 애플리케이션이 오라클과 완전히 다른 락킹 과 동시성 모댈을 가진 데이터베이 스로 개발되었다고 가
정해보자. 여러분이 애플리케이션을 한 데이터베이 스에서 다른 데이터베이 스로 이관하고자 할 때 여러
분은 이 프로그램이 여전이 다른 환경에서 정확히 동작한다는 것을 입증해야 하며 , 상당히 많은 변경을
해야 한다는 것을 보여줄 것이다.
자원 스케줄 애플리케 이션이 블로킹 읽기가 되는 데이터베이스에서 처음 구현되었다고 가정하고, 비 즈
니스 룰은 데이터베이 스 트리거로 구현되었다고 생각하자 (INSERT가 발생한 후 트랜잭션이 커잇되기 전에
42
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
그 시점의 테이블 안에 우리의 데이터가 존재하고 있다는 것을 입증해야 한다). 이렇게 신규로 삽입되는 데이
터 때문에 블로킹 읽기를 채택한 시스템에서는 테이블로의 삽입 처리가 직렬화되어야 한다. 처음 사람
이 ‘roorn A’ 에 끔요일 오후 ‘2:00-3:00’ 에 데이터 를 입력하고 겹친 것이 있는지 찾는 쿼리를 실행할
것이다. 다음 사람이 중복된 것이 있는지 찾고 요청사항을 입력하려고 시도하면, 이것은 블로킹이 될
것이다(이것은 새로 압력된 데이터 를 읽기가 가능해질 때까지 기다린다) 이런 블로킹 읽기 데이터베이스에
서 우리의 프로그램은 겉으로 보기에는 잘 동작하는 것처럼 보인다. 그렇지만 우리가 동시에 여러 로우
를 입력하고 각각의 데이터를 읽으려고 시도하면 데드락 (deadlock)(락을 다루는 장에서 설명할 개념이다)
이 쉽게 발생한다. 통일 자원에 대한 점검은 순서대로 일어나며 절대 동시에 발생할 수 없다.
만일 우리가 이 애플라케이션을 오라클에 이식하면서 그것이 같은 방법으로 잘 동작하라라 단순히 가
정한다면, 큰 충격을 받게 될 것이다. 로우 레벨 락을 사용하고 non-blocking 읽기를 지원하는 오라클
에서는 잘 통작하지 않는다. 앞서 다루었듯이 접근을 직렬화하기 위해서는 FOR UPDATE 절을 사용
해야 한다 FOR UPDATE 절이 없으면 두 명의 사용자가 동시에 같은 자원을 예약할 수 있을 것이다.
이것은 우리가 다루는 데이터베이스가 다중 사용자 환경에서 어떻게 동작하는지 이해하지 못한 직접적
인결과다.
필지는 데이터베이스 A에서 B로 애플리케이션을 이식할 때 이런 문제를 여러 번 경험했다. 데이터베
이스 A에서는 완벽하게 동작하던 프로그램이 데이터베이스 B 에서 겉으로 드러나 보일 정도로 이상하
게 동작할 때 데이터베이스 B가 ‘나쁜 데이터베이스’ 라는 생각이 제일 처음 생각난 것이다. 데이터베
이스 B는 단지 A와는 다르게 작동하는 것인데도 말이다. 어떤 데이터베이스도 틀리거나 나쁘지 않으
며, 단지 다를 뿐이다 그것들이 어떻게 동작하는지 알고 이해하는 것은 여러분이 이러한 이슈틀을 다
루는 데 큰 도움이 될 것이다. 오라클에서 작동하는 프로그램을 SQL 서버로 옮기는 것은 SQL 서버의
블로킹 읽기와 데드락 이슈에 노출시키는 것이다. 그 반대도 마찬가지다.
예를 들어 필지는 몇 개의 Transact SQL(SQL 서벼에서 저장 프로세서 역할을 하는 것)을 PL! SQL로 바꾸
어 탈라는 요청을 받았다. 이 일을 하던 개발자는 오리클 내부에 있는 SQL 쿼리들이 ‘틀린’ 결괴를 내
놓는다고불평했다. 이 쿼리는다음과같다.
declare
l_some_variable varchar2(25);
begin
if ( some_condition )
then
l_some_variable := f( ... );
end if;
for x in ( select * from T where x = l_some_variable )
43
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
loop
이 프로그램 의 목적은 T 안에서 몇몇 조건이 일 치 하지 않거 나 x가 몇몇 조건이 요구하는 특정한 값과
같다면 x가 NULL 인 모든 로우를 찾는 것 이다
사실 , 불만거리는오리를안에서 는 L_SOME_ V ARIABLE 에 특정한값이 대입되 지 않으면 (NULL로남
아 있으면) 어떤 데이 터도 나오지 않는다는 것 이다. Sybase나 SQL 서 버에서는 그렇지 않다. 쿼리 는 X
가 NULL로 세 팅 되 어도 로우 값을 찾는다. 필지는 Sybase나 SQL 서 벼 에 서 오리클로 전환하는 모든
프로그램들에 서 이 런 문제들을 발견하였다. SQL 서 버는 tri-valued 로직 안에서 동작하게 되 어 있고,
오2.}클은 ANSI SQL 이 요구하는 방법 대 로 NULL 비 교 로직을 구현한다. 이 러한 룰 안에서 x 값과
NULL을 비교하는 것은 참 또는 거짓이 다. 사실 NULL은 ‘알지 못하는 것’ 이다. 아래 쿼 리 를 보자
ops$tkyte@QRA1 0G> select * from dual where null=null;
no rows selected
ops$tkyte@QRA1 0G> select * from dual where null <> null;
no rows selected
ops$tkyte@QRA1 0G> select * from dual where null is null;
D
X
여러분이 처음 이 것을 보면 햇갈릴 수도 있다. 오라클에 서 NULL은 NULL과 같은 것도 아나 고 같지
않은 것도 아니다 SQL 서벼는 기 본적으로 위와 같이 비교하지 않는다. SQL 서버와 Sybase에서
NULL은 NULL과 같다 (SQL 서버 현재 버전에 서는 ANSI 표준을 따르도록 수정 되었다). 어떤 데이터베이
스의 처리 방법 도 틀리지 않다. 단지 다를 뿐이다. 그리고 모든 데이터베이 스는 사실 ANSI를 따르지만
(ANSI 표준을따른다는것이 꼭표준을 100% 지원한다는의미는절대 아니다) 여전히 다르게 동작한다. 거기
에는극복해야 할모호성 이전 기 능과의 호환성 문제 등이 었다. 예를들어 SQL 서버는 NULL 비 교
에 있어 ANSI 의 방법을 지 원하지만 기본 기 능은 아니다(그 러 기 에는 기존 벼 전에 구축되어 있는 수많은
프로그램을 훌어보아야 할 것 이다).
이 경우, 문제해 결을하려 면 아래와 같이 쿼리를 만들면 된다.
44
select *
from t
빼ere ( x = l_some_variable OR (x is null and l_some_variable is NULL ))
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
그러나 이것은 또 다른 문제점을 발생시킨다, SQL 서벼에서 이 쿼리는 x 에 대한 인텍스를 사용한다.
오라클에선 그렇지 않을 것이다. 왜냐하면 B*Tree 인텍스(인텍스를 다루는 장에서 살필 것이다)는 NULL
을 인텍스에 포함하지 않는다. 그러므로 NULL값을 찾을 필요가 있을 때 B*Tree 인텍스는 유용하지
않다 (역자 주 where x is null을 사용하면 × 컬럼에 인텍스 (B*Tree 인댁스)가 있다 하더라도 인텍스를 사용하지
못한다. 비트업 인댁스에서는 가능하다l.
I Note I 적어도 오라클 S*Tree 인텍스의 한 개의 컬럼이 NOT NULL로 정의되어 있는 한 테이블에 있는 모든 로우는 인
댁스를 생성할 수 있고. x is null인 콧에서 predicate는 로우를 뽑아내기 위해 인댁스를 사용할 수 있고, 사용할 것이다
이런 경우에 우리가 한 일이라고는 프로그램 코드의 수정을 최소화하기 위해 x 에 실제상황에서는 발생
하지 않는 어떤 값을 할당하는 것이다. 여기서 x는 양수로 정의되어 있었다 그러므로 우리는 숫자 -1
을선택했다. 따라서 쿼리는다음과같이 되었다
select * from t where nvl(x,-1) = nvl(1_some_variable,-1)
그리고 우리는 함수 기반 인텍스를 생성했다.
create index t_idx on t( nvl(x ,-1) )j
우리는별다른수정 없이 같은결과물을얻게 되었다. 이 샘플에서 알아야할중요한점은다음과같다.
• 데이터베이스들은 서로 다르다. 한 데이터베이 스에서의 경험은 부분적으로 다른 데이터베 이 스에
도웅이 되지만, 근본적인 차이점뿐만 아니라 아주 사소한 차이점에 대해서도 대비해야 한다.
· 사소한차이점 (NULL 처리 방법 등)이 근본적 인 차이점(동시성 제어 메커니즘같은만큼큰 영향을 미
칠수있다.
• 데이터베이스가 어떻게 동작하고, 이러한 문제들을 해결하기 위해 어떤 기능들을 적용하고 있는지
알아야한다.
개발지들이 하루에 한 번 이상 내게 묻는 질문이 있다. “저장 프로시저에 임시 테이블을 어떻게 생성합
니까” 등과 같은 데이터베이 스의 특정 기능 구현 방법에 대한 질문이다. 필자는 그런 질문에는 직접 대
답하지 않는다. 대 신에 필자는 “왜 이런 기능을 구현하려고 합니까?"라고 질문을 던진다 이 질문에 여
러 번 “SQL 서버에서는 저장 프로시저에 임시 테이블을 생성했고, 오리클에서도 그것을 할 필요가 있
습니다”라는대탑을들었다. 예상그대로다. 필자는이렇게 쉽게 대답한다. “여러분은오라클 저장프
45
전문가를 위한 오라클 데이터베이스 아키텍처 ‘ . .
로시저 내에서 임시 테이블을 만들고 싶은 게 아닙니다. 단지 그렇게 해야 하는 것으로 믿고 있을 뿐입
니다”라고 말이다. 사실, 오라클에서 임시 태이블을 생성해서 처리하는 것은 나쁜 방법이다. 만일 여러
분이 오라클의 저장프로시저에서 테이블을생성한다면 다음과같은사실을알게 될 것이다 .
• DDL 처리는 확장성을 방해한다
.DDL 처리는 빠르지 않다 .
• DDL 처리는 트랜잭션을 커빗해버린다.
• 저장프로시저에서 이 테이블에 접근하려면 정적 SQL 이 아니라동적 SQL을사용해야한다 .
• FL! SQL에서 동적 SQL은 정적 SQL처럼 빠르거나 최적화되지 않는다.
핵심은 오라클에서 임시 테이블을 펼요로 할 때조차도 여러분이 SQL 서버에서 한 것과 똑같이 하기 를
원하지 않는다는 것이다 여려분은 오리클에서 최적화된 것을 원한다. 오라클에서 SQL 서버에 다른 방
법으로 진행하려고 하는 것처럼 모든 사용자가 공유하는 임시 데이터 를 위한 임시 테이블을 생성하기
를 원하지 않을 것이다(이것은 오라클이 작동히는 방식이다), 이것은 다른 데이터베이스들에 확장성과 동
시성의 기능을제한한다. 모든데이터베이스는똑같이 만들어지지 않았다. 그것들은매우다르다.
오라클에서 임시 테이 블을 사용할 수 없다는 말이 아니다 하려면 할 수 있다. 여러분은 단지 SQL 서벼
에서 한 것을 오라클에서는 다르게 사용해야 한다(그 반대도 마찬가지다),
표즈이영하 a.:.,.-IOO
모든 데이터베이스가 SQL99 호환이라면 반드시 같아야 한다. 적어도 필자는 그렇게 생각한다. 그러나
이번 절에서 이런 맹목적인 믿음을 없애려 한다.
SQL99는 데이 터베이스를 위한 ANSI!ISO 표준이다. 이 것은 SQL92 ANSI!ISO 표준 다음에 나왔으
며, 그 이전엔 SQL89 ANSI! ISO가 있다. 지금은 SQL2003과 SQL2008 표준으로 갱신되었다. 표준은
데이터베이스가 어떻게 동작할 것인지 말해주는 언어 (SQL)와 동작(트랜잭션, 고립화 레벨 등)을 정의한
다. 여러분은 많은 상업용 데이터베이스가 어느 정도 SQL99 에 호환된다고 알고 있었는가? 여러분은
쿼리와 애플리케이션의 이식이 진행되는 한 표준이 별 의미가 없다는 사실도 알고 있었는가?
SQL92 표준부터 시작하자면 표준은 네 가지 레벨을 갖고 있다 .
46
• Entry-Ievel: 대부분의 벤더 들이 따르고 있는 표준 레벨이다. 이것은 그 이전 표준인 SQL89를 약
간 개선한 것이다 어떤 데이터베이스 벤더들도 이보다 더 높은 레벨에 대해 인증을 받은 적이 없
다. 사실 SQL 호환성을 인증하는 National Institute of Standards and Technology(NIST)는 더
이상 인증을 하지 않는다 1993 년 오라클 7 , 0이 NIST로부터 SQL92 entry-level 호환성 인증을 받
았을때 필자는그 인증을 위해 구성된 팀의 일원이었다.
• • • CHAPTER 01 성공적인 오라클 애를리케이션 개발
• Transitional 기능 집합 측면에서 이 레벨은 en띠r-level에서 intermediate-level로 가는 중간에
위치하고있다 .
• Intermediate : 이 레벨은 아래의 것들을 포함하는 많은 기능을 추가했다(아래 모든 목록을 다 적은
것은아니다) .
· 동적 SQL
• 참조 무결성을 위한 cascade DELETE
. DATE와 TIME 데이터타입
· 도메인
· 가변 길이 문자열
. CASE 문
• 데이터타입 간 CAST 함수
• FULL: 아래의 기능들이 추가되었다(역시 모든목록은아니다).
· 커넥션관리
• BIT 문자열 데이터타입
· 유예가능무결성제약
- FROM 절에 derived 테이블
. CHECK 절에 서브 쿼리
• 임시 태이블
entry-level 표준은 outer 조인, 새로운 rnner 조인 문장 등과 같은 기능은 포함하지 않는다.
transitional은 outer 조인과 inner 조인 문장의 기능을 포함하고 있다 intermediate는 더 많은 것을
포함하며 full은 당연히 SQL92 의 모든 기능을 갖고 있다. SQL92 에 관련된 책은 여러 가지 레벨 간의
구분을 두지 않는다. 이렇게 하면 오히 려 주제에 대해 혼동을 줄 것이다. 그것들은 SQL92 의 전체 기능
을 구현한 이론적인 데이터베이스가 어떤 모습일지 설명한다. SQL92 책을 집어서 책에 있는 모든 내
용을 SQL92 데이터베이스에 단순히 적용하는 것은 불가능하다. 핵심 내용은 SQL92 표준의 en띠level
수준 이상 적용되지 않을 것이라는 것이다. 여러분이 intermediate 또는 더 높은 단계의 어딴 기
능을 사용하려 한다면, 애플리케이션을 이식할 수 없는 위험을 안게 될 것이다.
SQL99는 적합성을 Core Enhanced 단 두 가지로 정의한다. 그것은 전통적 인 SQL보다 훨씬 더 많은
내용을 담고 있으며, 배열 , 콜렉션과 같은 객체관계형 구조를 소개한다. SQL MM (multi-media) 객체
47
전문가를 위한 오라클 데이터베이스 아키텍처 $1 8 8
관계형 타입과 같은 것 등을 커버한다. 어떤 데이터베이스도 SQL99 의 Core와 Enhanced를 준수하는
것에 인증을 받지 못했다. 사실 펼자는 자기 제품이 어떤 레벨의 표준사항이라도 준수하고 있다고 주
장하는 어떤 벤더도 알지 못한다.
여러분은 벤더에 특화된 기능을 사용하는 것을 두려워할 필요가 없다. 이런 특화된 기능을 샤용하는 데
이미 많은 비용을 지불하고 있다. 모든 데이터베이스는 그들 자신만의 기술을 갖고 있으며, 여러분은
항상 각각의 데이터베이스 안에 주어져 있는 기능을 수행할 방법을 찾을 수 있다. 이제 여러분이 사용
하고 있는 데이터베이스에 대해 최고의 기능을 시용o-}자. 그리고 다른 데이터베이스로 옮기게 되면 컴
포넌트들을 다시 적용하라. 이런 변경점들과 상관없이 수행하는 좋은 프로그램 기술을 사용하자. 여l를
들면 오라클 커널 개발자들과 같이 운영체제에 상관없이 수행되는 애플라케이션을 작성하는 사람들이
사용하는 기술들을 사용하자는 것이다.
여러분이 할 수 있다는 것을 확신하라
이 책의 목적은 여러분에게 가용한 기능들을 전부 시용할 수 있도록 돕는 것이다. 그러나 사항별로 그
때그때에 맞는 기술 기반 위에서 구현된 것을 변경할 수 있다는 점을 명심하기 바란다. 유사한 예로, 오
리클은 이식이 수월한 애플리케이션이다. 오라클은 많은 운영체제 위에서 실행한다. 그러나 윈도우즈
에서는 쓰레드나 윈도우즈에 특화된 기능들을 사용하면서 윈도우즈 방식으로 수행한다. 반대로, 유닉
스에서 오라클은윈도우즈에서 하던 일을각각의 개별 프로세스를사용하면서 다중프로세스 서버처럼
실행한다. 핵심적인 오리클의 기능은 두 개의 플랫폼에서 모두 사용 기능하지만, 매우 다른 방식으로
구현되어 있다. 여러 데이터베이스에서 기능해야만 하는 여러분의 데이터베이스 애플라케이션도 마찬
가지다.
예를 들어 많은 데이터베이스 애플리케이션의 공통 기능으로서 각 로우에 대한 유일 커(뻐que key)를
생성하는 것이 있다. 로우를 입력할 때 시스템은 입력한 로우에 대하여 자동으로 키를 생성한다. 오라
클은 이에 대해 시권스라고 하는 데이터베이스 객체를 제공하며 SYS_GUIDO라는 다른 함수도 제공
하고 있다. 인포믹스는 SERIAL 데이터타입을 가지고 있다. Sybase와 SQL 서버는 IDENTITY 타업을
가지고 있다. 각각의 데이터베이스는 유일 키 생성에 대한 해법을 보유하고 있다. 그러나 구현하고 결
괴를 뽑아내는 방법들은 서로 다르다. 따라서 이런 지식들을 많이 알고 있는 개발자들이라면 각 데이터
베이스별로 서로 다른 기능에 대해 대처할 수 있는 두 가지 방법에 대해 익히 알고 있을 것이다. 두 가
지방법은다음과같다.
• 유일 키를 생성하는 모든 데이터베이스에 독립적인 메서드를 개발한다.
• 각각의 데이터베이스에서 거를생성할때 서로다른수행을방법을수용하고다른 기술을사용한다.
첫 번째 방법의 이론적인 장점은 데이터베이스 이관을 할 때 아무 변경이 필요 없다는 것이다. 필자는
48
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
이것을 ‘이론적’ 장점이라부른다. 이런 방법의 단점은구현하려면 엄청난 일이기 때문이고, 이 해법은
실제로는 실행 불가능하기 때문이다. 완전히 데이터 독립적인 프로세스를 개발한다는 것은 태이블을
아래와 같이 생성하는 것과 같다.
ops$tkyte%ORA11GR2> insert into id_table values ( 'MY_KEY' ’ ø )j
1 row created.
ops$tkyte없RA11GR2> commit;
Commit complete.
새로운 키 를 얻기 위해 아래의 묘드를 실행해야 한다.

ID VALUE
간단해 보이지만아래와같은여러 가지 결과들을 얻을수 있다.
• 한 번에 한 사용자만 트랜잭션 로우를 처리할 수 있다. 카운터 를 증가시키려면 로우를 업데이트해
야 한다. 이것은 프로그램이 키 생성 작업을 직렬화하도록 할 것이다. 기껏해야 동시에 한 사용자
만새로운 키 값을생성할수 있다.
• 오라클에서는(다른 데이터베이 스는 다르게 작동할지도 모른다) 이 작업을 통시에 수행하려 하는 첫 번
째 사용자는 SERIALIZABLE 고립 레벨에서 “ORA-08177: can’t serialize access for this
transaction" 라는 오류를 만날 것이다
예를 들어, 개발자모르게 많은툴이 자동으로 기본적인 고협 모드로수행하는환경인 J2EE에서 자주
일어나는 SERIALIZABLE 트랜잭션을 사용한다면 다음과 같은 동작을 보게 될 것이다. 이 예제에서
49
전문가를 위한 오라클 데이터베이스 아키텍처 " • •
SQL 프롬프트는 세션 정 보를 담고 있다.
OPS$TKYTE session(261 ,2586)> set transaction isolation level serializable;
Transaction set.
OPS$TKYTE session(261 ,2586)> select id_value
2 from id table
3 where id name = ’ MY_KEY' ;
ID VALUE
2
다른 SQL*Plus 세 션으로 옮겨 서 유일한 아이디 를 동시에 요청하는 똑같은 작업을 할 것 이 다
OPS$TKYTE session(271 ,1231)> set transaction isolation level serializable;
Transaction set.
OPS$T에TE session(271 ,1231)> update id_table
2 set id value = id value+ 1
3 where id_name = 'MY_KEY ' ;
이 지점 에서 한 개 의 트랜잭 션만 로우를 업 데이 트하기 위해 블로킹 을 한다 이것은 첫 번째 가능한 결
괴를 보여 준다 락을 결고 로우가 처리되 길 기다린다. 그러나 오라클에서 SERIALIZABLE를 시용하기
때문에 첫 번째 세션의 트랜잭션에 커 빗을 할 때 다음의 처 리를 할 수 있다.
OPS$TKYTE session(261 ,2586)> commit;
Commit complete.
두 번째 세 션은 아래의 SQL을 실행한 즉시 다음의 오류를 보여 준다.
3ERROR at line 1:
ORA.08177: can't serialize access for this transaction
50
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
앞의 오류는 위의 커빗 명령과 상관없이 발생할 것이다 이런 현상은 트랜잭션이 시작한 후에 다른 세
션에서 수정한 자료를 수정하려고 하면 발생한다.
따라서 데이터베이스 독립적인 로직은 실제로는 전혀 데이터베이스 독립적이지 않다. ‘고립 (isolation)’
례벨에 따라 한 개의 데이터베이스에서조차 잘 동작하지 않을지도 모른다. 어떤 경우에는 클록킹하고
대기히-고, 어떤 때에는 오류 메시지를 낸다. 결과를 보려면 오래 기다려야 하거나 오래 기다려서 결국
오류를 보게 되는 두 가지 상황은 사용자에게 혼돈을 주는 매우 심각하고 극단적인 상황이다.
이 문제는 트랜잭션이 단순히 겉으로 보는 것보다 훨씬 복잡한 문제라는 것을 보여준다. 예제에서
UPDATE와 SELECT는 트랜잭션을 구성하는 수많은 쿼라 중 단순한 두 개의 쿼리에 불과하다. 아직
직전에 생성한 키를 테이블에 입력조차 하지 않았으며, 이 트랜잭션을 마무리하기 위한 다른 어떤 작엽
조차 하지 않았다. 직렬화는 확장성에 주요한 제한 요소가 될 것이다. 주문을 처리하는 웹 사이트에서
이런 기술의 영향을 생각해보자. 직렬화의 화두는 주문 변호를 어떻게 생성할 것인가의 문제다. 여기엔
다중 시용자 동시성이 없으므로 우리는 모든 것을 순차적으로 처리할 수밖에 없다.
이 문제에 대한 올바른 방법은 각 데이터베이스에 대해 최적화된 코드를 시용하는 것이다. 오라클에서
는 다음과 같이 하면 된다(생성된 프라이머리 키가 펼요한 태이블은 T라고 가정한다).
Ops$tkyte%ORA11GR2> create table t
2 (pk number primary key,
3 other_data varchar2(20)
4 )
5 /
Table created .
ops$tkyte%ORA11GR2> create sequence t_seq;
Sequence created.
ops$tkyte~oORA11GR2> create trigger t before insert on t
2 for each row
3 begin
4 :new.pk := t_seq.nextval;
5 end;
6 /
Trigger created .
I Note I 오라클 11g 이전 렬리즈에서 SELECT T_SEQ.NEXTVAL INTO :NEW,PK FROM DUAL;라고 사용해야 한다 오
라클 11g에선 이렇게 할당하는 것 대신 P L!SQL에서 sequence를 직접 할당하는 새로운 기능이 있다
51
전문가를 위한 오라클 데이터베이스 아키텍처 ..... .
이것은 입력된 각 로우에 자동으로 투명하게 유일 키를 할당할 것이다. 성능을 우선시하는 방법은 단순
하게다음과같다.
Insert into t ( pk, …. ) values ( t_seq.NEXTVAL, …. );
이것은 트리거의 간접 부하가 없이 실행된다(물론 이 방식은 필자가 절대적으로 선호히는 방식이다). 여러
분은 다른 데이터베이스에서도 이런 형식을 사용해서 똑같은 결과를 얻을 수 있다 CREATE TABLE
문법은 다르겠지만, 최종적인 결과는 같을 것이다. 여기서 우리는 블로킹을 걸지 않고 동시에 유일 커
를 생성하기 위하여 각각의 데이터베이스의 특정을 활용하는 법을 다루었다. 또한 모든 로직에 DDL 이
포함되어 있어서 애플라케이션 코드에 변경을 하지 않는 방법을 소개했다.
레이어 프로그래밍
일단 모든 데이터베이스가 서로 다른 방법으로 기능들을 구현한다는 개념을 이해하기만 하면, 이식성
좋은 프로그램을 만드는 또 다른 예는 필요할 때 데이터베이스 액세스를 계층으로 만들 수 있도록 한
다. JDBC를 사용하여 프로그램을 만든다고 하자. 여러분이 직접 SELECT, INSERT, UPDATE,
DELETE와 같은 SQL을 사용한다변 추상화 계층을 필요로 하지 않을 것이다 프로그램을 작성할 때
각각의 데이터베이스에서 지원하는 기능만 사용하여 애플리케이션을 구축하고, 하나의 데이터베이스
에 대해서만 검증한다면 (NULL=NULL 논의를 기억하라)SQL을 직접 코딩하는 것이 좋을지도 모른다.
비록 여러분은 분명히 필자가 아는 모든 사람보다 분명 더 많은 데이터베이스 지식을 보유하고 있을지
모르지만, 이것은 실현 기능성이 떨어지는 SQL을 작성하고 있는 것이다(결국, 모든 데이터베이스에 기반
을 두어 같은 작업을 할 수 있는지 알 수 있는 유일한 방법이다). 더 좋은 이식성과 더 나은 성능을 제공하는
다른 방법은 결과집합 (res비tsets)을 반환하는 저장 프로시저를 시용하는 것이다. 모든 벤더의 데이터베
이스는 저장 프로시저에서 결과집합을 반환할 수 있지만, 방법은 조금씩 다르다. 만들어야 할 실제 코
드는 데이터베이스마다 다르다.
여기 소개한 두 가지 선택은 결과집합을 반환하는 저장 프로시저를 사용하지 않거나 다른 데이터베이
스마다 다른 코드를 구현하는 것이다. 필자는 각기 다른 벤더틀의 메서드에 대해 다른 코드를 만들려고
하고, 저장프로시저를무겁게 사용하려 한다. 이런 방식은다른데이터베이스에 구현하는시간을증가
시키 는 것처럼 보인다. 그리나 다%댄 데이터베이 스에 대해 실제 이 방법을 구현하기가 생각보다 쉽다
는 것을 알게 될 것이다. 모든 데이터베이스에서 완벽하게 동작하는 SQL을 찾는 대신(실제로 어떤 것은
다른 데이터베이스보다 더 좋은 통작을 할지도 모른다) 해당 데이터베이스에 최적화된 SQL을 만들 것이다
이 일을 애플리케이션 외부에서 할 수 있으며 애플리케이션을 튜닝하는 데 더 큰 유연성을 준다. 여러
분은 애플리케이션을 패치하지 않은 재 데이터베이스 안에서 수행성이 낮은 쿼리를 수정할 수 있고, 수
정한 것을 즉시 적용할 수 있다.
52
• • • CHAPTEROl 성공적인 오라클 애을리케이션 개발
적용할 데이터베이스에 특화된 프로그램 코드를 개발하는 방식에 대한 또 다른 논쟁으로는 오라클,
SQL 서벼 DB2 세 가지 데이터베이스만으로 제한하더라도 데이터베이스들 간에 미묘한 차이를 충분
히 이해할 정도로 유능한 개발자(팀은 말할 것도 없다)를 찾기가 사실상 불가능하다는 것이다. 필자는 지
난 16 년 동안 오라클을 기반으로 대부분 일해 왔다. 필자는 오리클을 사용하면서 새로운 기능에 대해
매일 배운다. 물론, 필자가 위의 세 개의 데이터베이스에 대해 정통하고 이 세 데이터베이스 간의 차이
가 무엇인지 이해하며, 이 차이가 개발해야 하는 ‘일반화 프로그램’ 층에 어떤 영향을 마지는지 안다고
말하는 것은 거짓말일 것이다. 모든 데이터베이스를 정확하게 알고 개발하는 것이 정확하고 효율적이
라 할 수 있을지도 의심스럽다. 또한 여기서 우리는 필자뿐 아니라 개발자 여러분 개개인들에 대해 말
하고 있다. 세 개의 데이터베이스는 고사하고 현재 시용하고 있는 하나의 데이터베이스라도 충분히 이
해하고 사용하거나 사용하고 있는 개발자가 얼마나 있을까? 안전하고 확장성이 좋고, 데이터베이스 독
립적인 루틴을 개발할 수 있는 개인을 찾는 것은 거룩한 성배를 찾는 것과 같이 어렵다 이런 일을 할
수 있는 개발팀을 구성하는 것은 불가능하다. 오라클 전문가 DB2 전문가 SQL 서벼 전문기를 찾아서
“우리는 X, Y , Z를 실행할 트랜잭션을 필요로 합니다”라고 말하는 것은 비교적 쉽다. 그들은 입력값과
필요한 출력값과 비즈나스 프로세스 기능 설명을 듣고 이것을 기초로 저장 프로시저 같은 트랜잭션
API들을 만들어서 리포트 양식을 맞춘다. 각각의 API들은 특정 데이터베이스에 대해 각각 유일한 기
능들을 사용해서 최고의 방법으로 구현될 것이다. 이런 개발자들은 사용하고 있는 데이터베이스 플랫
폼의 모든 능력 (부족하더라도 기능한 최대한의 능력 )을 자유롭게 사용한다.
다중 플랫폼 코드를 개발하는 개발자가 사용하는 같은 기술들이 있다. 예를 들어 오리클 회사는 오라클
을 개발할 때 이 기술을 사용한다. 데이터베이스 전체 코드에 비교하면 작은 부분이겠지만, 모든 플랫
폼에 특화되어 구현된 OSD(Operating System Dependent) 코드라고 불리는 많은 코드가 있다. 오라클
은 이런 추상화 레이어를사용하여 데이터베이스 자체 코드를수정하지 않고 성능과통합을 위해 많은
운영체제의 본래 특정을 사용할 수 있다. 오라클이 윈도우즈에서 멸티 쓰레드 애플리케이션으로 수행
하고, 유닉스에서는 멀티프로세스 애플라케이션으로 수행한다는 사실은 이러한 특정을 입증한다. 내부
프로세스 통신을 위한 메커니즘은 어떤 레벨에 잘 추상화되어 있어서, 각기 다른 운영체제 기반으로 재
적용펼 수 있다. 따라서 사용되는플랫폼에 대해 직접적으로 특화되어 작성된 애플리케이션으로서 수행
되게된다.
SQL 문법의 차이, 구현의 차이, 다른 데이터베이스에 사용되는 같은 쿼리의 성능 차이 외에도 동시성
제어, 고립 레벨, 쿼리 일관성 등의 문제들이 었다. 우린 이런 것들을 7장 ‘일관성과 멀티버저닝’에서
자세하게 디룰 것이며, 이런 차이점이 어떤 영향을 미치는지 알게 될 것이다. SQL92 / SQL99는 트랜잭
션의 작동 방식과 고립 레벨이 구현되어야 할 방볍에 대해 간단한 정의를 제공하려고 시도했다. 그러나
결국 다른 데이터베이스들에서 다른 결괴를 얻어야만 했다. 이런 결과는 모두 구현 방식의 차이 때문에
발생한다. 하나의 데이터베이스에서 어떤 애플라케이션은 사방에서 데드락과 블로킹이 걸린다. 반면
53
전문가를 위한 오라클 데이터베이스 아키택처 • • •
다른 데이터베이스에서는 같은 애플리케이션이 부드럽게 잘 동작할 것이다. 하나의 데이터베이스에서
물리적으로 일련화하는 블록이 장점으로 사용되었지만, 다른 데이터베이스에 그것을 적용할 때 , 블로
킹을 걸지 않고 잘못된 결과값을 얻을 수 있다. 하나의 데이터베이 스에서 애플리케이션을 집어서 다른
데이터베이스에 떨어뜨리는 것(무작정 이식하는 것)은 표준에 100% 맞추어 개발했더라도 많은 어려운
작업과노력 이 든다
특징과함수들
반드시 데이터베이 스 독립적으로 만들려고 할 필요가 없다는 주장은 여러분이 사용하는 데이터베이 스
가 제공하는 것이 무엇인지 이해하고 그것을 완전히 사용해야 한다는 주장과 일맥상통한다. 이 절은 오
라클 l1 g가 제공하는 모든 특정을 소개하는 것이 아니며, 특정을 자세하게 소개하는 그것만으로도 엄
청니케 큰 부피의 책이 될 것이다. 오라클 9i, 10g, 그리고 l1 g의 새로운 특정들은 오라클 문서 에 잘 정
리되어 있다. 오라클에서 만 페이지가 넘는 자료를 제공하고 있으며 모든 특정과 기능을 다룬다는 것
은 정말 힘든 일 이 다. 대신 이 책은 각 릴리즈에서 제공하는 기능에 대해 최소한의 지식이라도 얻는 것
이 얼마나 유익한지를 증명할 것 이다.
앞에서 말한 것처럼 펼자는 웹에서 오라클에 대한 질문에 답을 달아주고 있다. 답변 중 80%는 단순히
문서 에 URL을 알려주는 것 이라 말했다(여러분도 알듯이 내가 답을 드리는 대 부분의 것은 문서의 위치다.
“이것을 읽어 보세요”라는 답으로 대신히는 질문도 두 개 이상 있다). 사람들은 데이터베이 스의 내부 또는 외부
에서 어떻게 복잡한 기능을 작성하는지 그 방법에 대해 질문하고 필자는 그들에게 오리클이 이미 그들
이 원하는 특정을 만들어 놓았다는 것과 어떻게 그것을 사용하는지 말해주는 문서의 위치를 알려준다.
이미 실행된 리터럴 SQL 을 볼 수 있는 뷰자 있습니까? 제가 의미하는 것은 V$SQL 에서 :
INSERT INTO TABLEl (C0L1,COL2) VALUES (:1 , :2)라는 SQL TEXT가 실행되었을 때 실저제/
값이 대압된 대로의 SQL을 보고 싶습니다다. 예를 들면 INSERT INTO TιABLEl ι(COL디1 ,,’ COL2긴)
VALUES ('F’i꺼r따S상stμV셔aιaI
u때pd따ate 또는 delete 문의 목록이며, 이것과 같은 SQL 문을 두 번째 스커마에 같은 실행 순서로
수행하고 싶습니다. 저는 아래와 같이 쓰고 싶습니다.
Select SQLJULLTEXT from V$SQL where FIRST_L띠ι TIME > SYSDATE-(1 /24) AND ...,
(SQL_TEXT like ’ INSER7똥 ’ . .. ) order by FIRST_ LOAD_ TIME
이런 자료를 웹 서비스를 통해 문장들을 처리할 스키마2 로 되내려고 합니다. 이것이 가능할까
요?
여기 데이터 복제를 하고 싶어하는 사람이 있다. 그는 SQL 문들을 얻을 수 있었다. (다행히도 1) 그러나
만일 그가 혹여 얻었다 하더라도 이 런 방식으로는 절 대로 동작하지 않는다. 절대로 동시에 실행된 SQL
54
• • • CHAPTER 01 성공적인 오라클 애를리케이선 개발
문의 결과를 구할 수 없다(두 개의 SQL 문이 정확히 동시에 실행된 멀 티 CPU 서버에서는 어떤 일이 일어날
까7). 또한 차례대로 실행할 수 없다(처리를 끝났을 때 다른 결괴를 보여줄 것이다). 여러분은 원래 시스램
에 있었던 동시성까지도 정확히 재현해서 쿼리 를 돌려야만 할 것이다.
예를 들어보자. 여 러분과 필자 둘 다 INSERT INTO A_TABLE SELECT * FROM A_TABLE을 통시
에 실행한다면 A_TABLE에는 우리가 시작할 때보다 3배가 많은 로우를 갖게 될 것이다. A_TABLE 이
100 7B 의 데이터로시작하고필자가 INSERT 문을실행하면 이제는 2007B 의 데이터 를 가질 것이다 여
러분이 내가 처리한 바로 뒤 커멋을 하지 않았을 때에 INSERT 문을 실행하면, 200 7B 의 데이터 를 보는
것이 아니라 1007H 의 데이터를 A_TABLE 에 더 입력하여 3007H 의 데이터가될 것이다 만일 우리가웹
서비스가 이런 insert를 하도록 변경하여 A_TABLE 이 100에서 200개의 데이터가 되고, 그 후 여러분
이 재차 입력해서 A TABLE 이 200에서 400 7H 의 데이터가 된다면 문제는 심각해진다. 데이터 복제는
쉬운 일이 아니다. 매우 어렵다. 오라클(그리고 다른 데이터베이 스들)은 10 년 이상 데이터 복제
(replication) 기능을제공하고 있다. 구현과유지보수에 많은노력이 수반된다.
여러분은 자신만의 복제 프로그램을 만들 수 있으며, 아마도 매우 재미있는 작엽이 될 것이다. 그러나
하루가 다 지나갈 쯤이 되어서는 더 이상 재미있는 작업이 아니라는 것을 알 것이다. 데이터베이스는
많은 일을 하며, 일반적으로 우리가 직접 만들어 하는 것보다 잘 해낸다. 예를 들어 복제 기능은 데이터
베이스 커널에 내장되어 있으며 C로 작성되었다. 빠르고, 사용하기도 쉽고 견고하다. 여러 버전과 여
러 플랫폼에서도 상관없이 실행된다. 문제가 생겼을 경우엔 지원팀의 도용을 받을 수도 있다 업그레이
드 시에는 아마도 몇 가지 새로운 기능과 더불어 ‘복제’ 기능도 지원된다. 자 이래도 여러분은 직접 복
제프로그램을 개발하겠는가? 직접 개발하면 지원하기 원하는 모든 버전에 대한 지원을 제공해야만 할
것이다. 구 버전과 신 버전 사이의 정보처리 상호운영 가능성? 이것이 여러분이 해야 할 일이 될 것이
다. 만일 프로그램이 깨지면, 지원팀 을 부를 수도 없을 것이다. 최소한 기본적인 이슈를 시연하기에 충
분한 작은 테스트 케이스를 얻을 때까지는 그렇다. 오리클의 새 버전이 렬리즈될 때마다 그것 에 맞추어
직접 만든 복제 프로그램을 이관하거나 수정해야 할 것이다.
새로운기능바로알기
데이터베이스에서 여러분이 사용할 수 있는 기능에 대해 완전히 이해하지 못하면, 오히려 이런 기능들
은 여러분을 괴 롭히는 문제가 되어 돌아온다. 필자는 다른 데이터베이스들을 기반으로 데이터베이스
애플리 케이션을 몇 년 동안 개발한 경험이 있는 몇몇 개발자들과 일한 적이 있다. 그들은 건강관리와
관련이 있는 임상 데이터 를 다루는 작업과 관련된 추이, 리포트, 시각화 소프트웨어를 포함하는 분석
소프트웨어를 작성했다. 그런데 이 개발자들은 인라인 뷰, 분석 함수 스칼라 서브쿼랴 등의 SQL 문의
기능을 몰랐다. 그들의 중요한 문제는 한 개의 부모 테이블과 두 개의 자식 테이블에 있는 데이터 를 분
석할 필요가 있다는 것이다. ‘엔티티 관계 다이어그램 (ERD)’은그림 1-1과같이 생겼다.
55
전문가를 위한 오라클 데이터베이스 아키렉처 • • •
그림 1-1 1 간단한 ERD
개발자들은 두 개의 자식 테이블들로부터 데이터를 종합해 부모 태이블의 자료를 기초로 리포트를 작
성해야 했다. 그들이 과거 경험했던 데이터베이스들은 ‘서브 쿼리 팩토링 (WITH 절)’ 을 제공하지 않았
고, 테이블을 직접 조회하는 대신 ‘쿼리를 다시 쿼리하는’ 기능인 인라인 뷰 기능을 제공하지 않았다.
이런 기능이 있는지조차 몰랐기 때문에 미들 티어에 그들 자신이 만든 보잘 것 없는 데이터베이스를 만
들었다. 그들은 부모 테이 블을 쿼리하고 응답 결과, 각각의 로우에 대해 자식 메이블로부터 데이터 를
종합하는 쿼리를 수행했다. 고객이 수행하기 원하는 하나의 쿼리는 결국 수천 개의 작은 쿼리 를 돌리는
결과가 되었다 아니면 그들은 모든 자식 테이블의 모든 값의 합산값을 미들 티어 메모리의 해시 테이
블에 넣고 해시 조인을 할 것이다.
요약하면, 그들은 임시 테이블스페이스와 복잡한 쿼리 용티마이저와 같은 것들의 장점을 사용하지도
못하고, nested join과 비 슷한 기능을 수행히는 데이터베이 스를 재개발하고 있는 것이다. 그들이 구입
한 데이터베이스가 갖고 있는 같은 기능을 수행하는 소프트웨어를 만들려고 온 시간을 소모해가며 개
발하고, 디자인하고, 튜닝하고, 성능을 높이려 했다. 그렇게 시간을 허비하는 동안 고객은 얻지도 못할
새로운 기능을 요구하고 있었다. 대부분의 개발 시간이 이 리포트 ‘엔진’ 개발에 소모되었기 때문이다.
재미있는 것은 이런 리포트 엔진은 실제로 데이터베이 스에 있는 기능이었다.
필자는 그들에게 각기 다른 레 벨 에 저장되어 있는 데이터 를 비교하기 위해 두 개의 집합을 조인할 수
있다는것을보여주었다 목록 1 -1 에서 1-3까지 설명한것처럼 여러 가지 방법이 가능하다.
목록 1-1 1 쿼리 안에 쿼리를 실행하는 인라인 뷰
56
select p.id, c1_sum1 , c2_sum2
from p,
(select id, sum(ql) cl_suml
tr‘om cl
group by i이 CI,
(select id, sum(q2) c.ζsum2
trom c2
group by id) c2
where p.id = c1.id
and p.id = c2.id
• • • CHAPTER 01 성공적인 오라클 애플리케이션 개발
목록 1-2 I 각 로우마다 서로 다른 쿼리를 실행하는 스칼라 서브쿼리
select p. id,
(select sum(ql) from cl 뼈er‘e c1. id = p.id) cl_suml,
(select sum(q2) from c2 뼈ere c2.id = p.id) cζsum2
from p
빼ere p.n때le = ’ 1234 '
목록 1-3 I WITH 절을 활용한 서브쿼 리 팩토링
with c1 vw as
(select id, sum(ql) cl_suml
from cl
group by id),
c2 vw as
(select id, sum(q2) cζsum2
from c2
group by id),
cl c2 as
(select CI.id, cl.cl_suml, c2.c2_sum2
/
이 목록에서 본 것 에 덧붙여 LAG , LEAD, ROW_NUMBER, r뻐k 함수 등과 같은 분석 함수를 사
용하면 더 엄청 난 일을 할 수 있다 개 발지들이 그들의 미 들 티어 데이터베이 스 엔진을 어 떻게 튜닝할
지를 고민하면서 수많은 시 간들을 날려 버 리고 어 떤 잘못된 작업 방법을 선택했는지를 그 자리에서 보
여주기 위해 SQL*Plus를 사용하여 rSQL Reference Guide.J 를 빔 프로젝터로 보여주었다. 최종 목표는
더 이상 미 들 티어를튜닝하는것이 아니라기능한빨리 미들티어를걷어 내는것이 었다
또 다른 예를 보자. 파이프 (데 이터베이스 IPC 메 커 니즘)의 메시 지를 읽는 오리클 데이 터 베이스 안에 데몬
프로세스를 개발하여 구동하는 개발지들이 있었다 이 데몬 프로세스들은 파이프 메시 지 안에 있는
SQL을 실행하고 작업 결괴를 커빗한다. 데몬 프로세스들의 작업들로 말미 암아 더 큰 트랜잭 션이 실행
되면 롤백할 수 없는 트랜잭 션 내 부에 서 감사 기능과 오류 로깅 기능을 실행할 수 있었다. 보통, 트리 거
와 같은 기능은 데이 터 에 액 세스하는 것을 감사하는 데 시용되는데 니중에 쿼 리가 실 패하면 모든 작업
은 롤백할 수 있다. 따라서 다른 프로세스에 메시 지를 보내는 방법으로 분리된 트랜잭션 이 작업을 수
행하고 커멋을 할 수 있게 한다. 부모 트랜잭션을 롤백하더라도 감사 레코드는 없어지지 않고 있을 것
이 다 오라클 8i 이 전 벼 전에서 위와 같은 방법으로 기능을 구현하는 것이 유일한 방법이었다. 펼자가
57
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
개발자들에게 지율 트랜잭션 (autonomous transactions)이라 하는 데 이터베이스의 기능을 이야기했을
때 놀라지 않는 이들이 없었다. 단 한 줄의 코드로 구현되는 자율 트랜잭션은 개발지들이 하던 일들과
정확히 같은 일을 했다. 긍정적으로 본다면, 불필요한 많은 프로그램 코드를 생산할 필요도, 유지보수
하는 데 시간을 허비할 필요도 없게 됐다. 그뿐만 아니라 시스램은 전반적으로 더 빠르게 실행되었고
이해하기도 쉬웠다. 개발자들은 자신들이 쓸데없이 허비한 많은 시간에 속상해했다. 특히, 그 데몬 프
로세스를 개발한 개발자들은 단지 쓸데없는 프로그램을 만들었다는 것에 아주 속상해했다.
데이터베이스가 이미 기능으로 제공하는 문제에 대한 해법에 대해 복잡한 솔루션을 개빌F하느라 시간을
소모하는 이런 종류의 예들은 많이 있다. 펼자는 이런 것들에 대해 책임을 통감한다. 필자가 고객이었
을 때 오라클의 세일즈 컨설턴트가 엄청난 양의 오라클 문서에 둘러싸여 있는 필자를 본 날을 아직도
기억한다. “이것이 모두 사실인가요?"라고 그에게 물으며 며칠을 문서의 내용을 파헤치며 읽는 데 할
애했다. SQL/DS, DB2, Ingress, Sybase, Informix, SQLBase, 오리클 및 기타 여러 데이터베이스를
가지고 일해 왔기에 데이터베이스에 대해 모두 알고 있다는 큰 착각에 빠져 있었다 각각의 것 이 제공
하는 것을 알기 위해 시간을 할애하기보다 필자가 작업하던 업무에 다른 데이터베이스에 서 습득한 지
식을 단순히 적용하려고만 했다 (Sybase나 SQL 서벼로 옮기는 것은 내게 가장 큰 충격이었다 다른 이기종 서
버 간의 이식과는 아주 다르게 작동했다). 오라클이 할 수 있는 것들을 실제로 찾아내면서 필자는 오라클의
장점을 사용하기 시 작했고, 더 작은 양의 코드로 더 빠르게 옮길 수 있었다(물론, 다른 데이터베이스도 마
찬가지라고 말하는 것이 공평하겠다). 1993 년의 일이다. 거의 20년이나 지났지만, 지금도 같을 것이다.
사용할 수 있는 기능이 무엇인지 열심히 공부하기 바란다. 소 잃고 외양간 고칠 펼요는 없지 않은가?
필자도 여전히 오라클에 관해 매일 새로운 것을 배우고 있다.
문제를 단순하게 해결하기
문제를 해 결하는 것엔 항상 쉬운 길과 어려운 길 두 가지의 길 이 있다. 일부러 어려운 길을 선택하는
사람들을 자주 본다. 물론 의식적으로 어려운 길을 자초해서 가지는 않을 것이다. 몰라서 그런 것이다.
데이터베이스가 ‘그것’ 을 할 수 있다고 기대하지도 않는다. 이에 비해 필자는 데이터베이스가 무슨 일
이든 할 수 있을 것이라고 기대하고 절 대 로 그것을 할 수 없다는 것을 발견할 때에만 (내가 직접 개발하
면서) 어려운 방법을 선택한다.
필;z}는 종종 “어떻게 사용자가 데이터베이 스 세션을 최대 하나만 가지도록 강제할 수 있나요?’라는 질
문을 받는다(여기에 소개할 수 있는 예가 수백 개는 된다) 이것은 많은 애플리 케이션의 필요조건이어야 하
지만, 필자가 한 번도 다루어보지 않은 것들이다 안타깝게도, 필자는 아직 사람들을 이런 방법으로 제
한하는 합당한 이유를 찾지 못했다. 그러나 사람들은 그 일을 하기를 원하고, 일반적으로 어려운 방법
을 사용해서 해 결한다. 예를 들어보자. 개발자들이 V$SESSION 테이블을 찾고, 한 개 이상의 세션을
가진 사용자 세션을 임의로 죽이는 배치 잡을 만들고 운영체제에서 실행한다. 또 다른 방법으로는 새
58
• • • CHAPTER 01 성공적인 오라클 애틀리케이션 개발
로운 테이블을 생성하고, 시용자가 로그인을 하면 로우를 입력하고, 로그이웃하면 그 로우를 삭제하는
애플리케이 션을 만든다. 이런 구현 방법은헬프데스크에 수많은전화문의를하도록한다. 왜냐하면 애
플리 케이 션이 깨진다 해도 로우는 절대 삭제되지 않기 때문이다. 필자는 다른 창조적인 방법을 많이 보
아왔지만, 어떤 것도 다음 것처럼 쉬운 것은 없다.
ops$tkyte%ORA11GR2> create profile one_session limit sessions-per_user‘ 1;
Profile created.
ops$tkyte%ORA11GR2> alter user scott profile one_session;
User altered.
ops$tkyte%ORA11GR2> alter system set resource_limit=true;
System altered .
ops$tkyte뼈RA11GR2> connect scott/tiger
COnnected.
scott%ORA11GR2> host sqlplus scott/tiger
SOL*Plus: Release 11.2.0.1.0 Production on Wed Dec 9 16:02:392009
Copyright (c) 1982, 2009, Oracle. All rights reserved.
ERROR:
0RA-02391: exceeded simultaneous SESSIONS PER USER limit
Enter user.name:
얼마나 간단한가? 이제 ONE_SESSION 프로파일을 가진 어떤 사용자라도 한 번만 로그인할 수 있다.
펼자가 이 해법을 꺼냈을 때 보통의 경우는 “아 지금까지 저런 방법이 있는지 몰랐다니”라며 손으로
이마를 치며 탄식하곤 한다. 여러분이 가지고 있는 도구가 할 수 있는 일이 무엇인지 익숙해지기 위 해
시간을 투자한다면, 개 발할 때 많은 시간과 에너지를 아낄 수 있을 것 이다.
‘단순하게 하기’ 라는주장은 더 넓은 영역인 아키텍처 레벨에도 적용된다. 개발지들이 매우복잡한 방
법을 채택하기 전에 좀 더 주의 깊 게 생각하라고 충고하곤 한다. 여러분의 시스템에서 움직 이 는 부분이
많을수록 더 많은 오류가 생길 수 있다. 너 무 복잡한 아키텍처에서는 정확히 어디서 오류가 발생하는지
찾기 어렵다. 아주 많은 티어를사용하여 구현하는 것은 매우 ‘매력적인 것’으로 보일 수 있지만, 단순
한 저장 프로시 저가 그것을 더 좋고, 더 빠르고, 더 작은 자원을 차지하면서 할 수 있다면, 그것은 바른
선택이아니다.
끝도 보이지 않고, 몇 달 동안 계속되고 있는 애플리케이션 개발 프로젝트들을 본 적 이 있다. 개발자들
은 최신 기술과 가장 훌륭한 기술과 언어 를 사용하고는 있지만, 이상하게 개발은 느리게 진행된다. 결
59
전문가를 위한 오라클 데이터베이스 아키텍처 • • •
코 무겁거나 복잡한 애플리케이션이 아니었다 어쩌면 매우 단순한 프로그램이 문제였을지도 모른다.
만일 여러분이 개집을 짓겠다고 무거운 기계를 비싼 돈을 들여 구매하지는 않을 것이다. 그러나 아파트
단지를짓는건설현장이라면수백 명의 인원을동원할것이며, 큰기계들을사용하는등작은목공일과
는 전혀 다른 공구를 사용할 것 이다, 애플리케이션 개발도 마찬가지다. ‘완벽한 아키텍처’ 는 존재하지
않는다 ‘완벽한 언어’ 도 존재하지 않는다. ‘완전한 처리 방법’ 도 존재하지 않는다. 그때그때 다르다.
필자의 경우를 예를 들어보겠다 필자의 개인 웹 사이트를 구축하기 위해서 필자는 APEX (Application
Express)를 사용했다. 작은 애플라케이션으로서 한두 명의 개발자가 만들었다. 아마 20개의 화면을 가
지고 있을 것이다 이 정도의 구현을 위해서는 PL/SQL과 APEX가 올바른 선택이다. 수십 명의 사람
도, 자바코딩, EJB 구축, 하이벼네이트 도입 등과같은 일도 필요하지 않은 간단하게 풀수 있는문제
였다. 복잡하고 큰 규모의 대형 애플리케이션은 몇 개 없다(요즘은 HR 시스템이나 ERP 시스템 등과 같은
큰 애플리케이션 대부분은 구입한다). 그러나 무수히 많은 작은 애플리케이션들이 있다 이런 일에 적당한
처 리 방법과 도구를 사용할 펼요가 있다.
필자는 언제든 복잡한 문제를 해결할 수 있는 가장 간단한 아키텍처를 지원할 것이다. 보상은 엄청날
수 있다. 모든 기술에는 적절하게 쓰일 만한 자기만의 자리가 있는 법이다. 모든 문제가 못과 같이 작은
것은아니다 따라서 우리는망치보다큰도구를공구상자에서 꺼내사용할수도있다.
개방성
어떤 이유인지는 모르겠으나 일부러 힘든 방법으로 일하는 사람들을 종종 보게 되는데, 이들이 겪는 어
려움은개방성과독립성과관련된문제들이다. 개방성과독립성은무슨수를쓰더라도꼭지켜야한다.
개발지들은 저장 프로세스나 시권스와 같이 간단한 기능이라도 폐쇄적이고 해당 데이터베이스에서만
작동하는 기능을 피하고 싶어한다. 그렇게 개발하면 특정 데이터베이스 시스램에 종속되기 때문이다.
물론 여러분이 읽고 쓰는 애플리 케이션을 개발하는 순간 이미 그것에 어느 정도 종속되는 것이 사실이
다. 쿼리를 수행하고 수정히는 순간 데이터베이스들 간에 미묘한(아니 미묘한 정도가 아닐 수도 있는) 차
이를 알게 될 것이다 어떤 데이터베이 스에서 SELECT COUNT(*) FROM T를 수행하면 두 개의 열을
갱신하면서 데드락을 발생시킨다. 반면 오리클에서는 SELECT COUNT(*)는 데드락을 발생시커지
않는다. 하나의 데이터베이 스에서 데드락이 발생되는 비즈니스 룰이 다른 데이터베이스에서는 데드락
이 발생하지 않는 경우도 있다. 데이터베이스의 기본적인 차이점 때문에 같은 쿼리가 데이터베이스에
따라 다른 결과가 나오는 경우도 많이 있다. 아무런 변경 없이 이기종 데이터베이 스로 이식하는 것은
매우 드문 일이다 (NULL=NULL 예처럼) 데이터베이스 간에 쿼리의 해석과 처리하는 부분에서의 차이
점은 앞으로도 항상 존재할 것이다.
하나의 프로젝트에서 개발자들이 비주얼 베이직 ActiveX 컨트롤 IIS 서버 오라클 데이터베이스를 이
용해서 웹 기반 프로덕트를 개발하는 것을 본 적이 있다. 개발자들은 PL / SQL로 비즈니스 로직을 구현
60
• • • CHAPTER 01 성공적인 오라클 애틀리케이션 개발
했기 때문에 그 제품이 데이터베이스 종속적이 되버렸다고 생각했고 필자에게 “어떻게 이 부분을 수
정할 수 있습니까?"라고 질문했다.
이 질문에 다소 놀랐다. 구현된 기술틀을 살펴보면서 데이터베이스 독립적이라는 개념이 얼마나 ‘나쁜
것 ’ 인지 설명해야만 했다.
• 시스템에 종속될 수밖에 없는 언어를 사용해 개발했다(자바를 사용했어야 했다).
• 시스템에 종속될 수밖에 없는 컴포넌트 기술을 선택했다 Ü2EE를 사용해야만 했다).
• 한 개의 플랫폼에서만 사용 기능한 웹 서벼를 선택했다(왜 아파치를 사용하지 않았는개).
개발자들이 선택한 각각의 기술들은 특정한 프로그램만 사용할 수 있는 것들이었다. 사실 운영 시스템
관점에서 다OcJ=한 선택을 제공할 수 있는 유일한 기술이라면 데이터베이스밖에 없었다.
이것과 상관없이 (그들은 이 기술들을 선택한 합당한 이유가 있어야만 한다) 우리 옆에는 여전히 그들의 아키
텍처에 위험한 컴포넌트의 기능을 사용하지 않기로 한 개발자들이 있다. 필자는 여러분이 기술을 신중
하게 선택하고 기능한 최대한으로 그것들을 이용할 거라는 믿음을 갖고 있다. 여러분은 이러한 기술에
많은 돈을 지불했고, 그것들을 충분히 이용하는 것에 최대의 관심이 있지 않은가? 그들은 다른 기술들
의 잠재적인 능력들을 사용하고자 하는 기대감에 부풀어 있었다고 생각했다. 그렇다면 왜 데이터베이
스에 대해서는 예외인개 데이터베이스는 개발자들이 성공적으로 개발하는 데 결정적인 역할을 하기
에 이 질문에 대답하기 더욱어려웠다.
개방성이라는 관점에서 생각해볼 때 이 주장과는 약간은 다른 긍정적인 면을 볼 수 있다. 여러분은 모
든 데이터를 데이터베이스에 넣는다. 데이터베이스는 매우 개방적인 도구이다. 데이터베이스는 크고
다%딴 개방 시스템 프로토콜과 액세스 메커니즘을 통해 데이터 접근을 지원한다. 세상에서 가장 개방
적인 것이란말은당연히 멋진 말로들린다.
또한 여러분은 모든 애플리케이션 로직과 더 중요한 보안을 데이터베이스의 외부에 놓는다. 아마도 데
이터를 액세스하는 자바 빈 컴포넌트 때문일 것이다 이런 현상은 데이터를 액세스하는 JSP 때문일지
도 모른다 Microsoft' s Transaction Server(MTS) 기반에서 수행하는 비주얼 베이직 코드 안에 보안
과 관련된 모률이 있을지도 모른다. 어쩌면 하이버네이트가 생성한 코드 안에 있을 수도 있다. 최종적
인 결과는 여러분은 데이터베이스를 막아버린 것이며, 그것을 ‘비개방’ 적으로 만들었다. 더 이상 사람
들은 특정한 데이터를 시용하기 위해서는 특정한 기술이 있어야만 한다고 고집할 수 없게 된다. 그들은
당신이 만든 액세스 메서드를 사용해야만 하거나 보안을 전부 건너 뛰어야 한다 최근에는 얼핏 타당한
말로들릴지 모르지만, 여러분이 반드시 기억해야할것은오늘의 최고의 기술이 어제의 개념이며, 내
일의 오래되고 낡은 기술이라는 것이다. 관계형 데이터베이스의 세계(아마도 대부분의 객체 구현들도 마
찬가지지만)에서 30년도 넘는 세월 동안 계속 지속된 것은 데이터베이스 그 자체뿐이다. 데이터의 앞단
61
전문가를 위한 오라클 데이터베이스 아키텍처 • ••
은 거의 해마다 바뀌고, 데이터베이스 내부가 아닌 자체적으로 구현된 모든 보안 솔루션을 갖고 있는
애플리케이션은 미래로 나가는 데 장벽이 된다.
오라클 데이터베이스는 fine-grained access control (FGAC) 라는 기능을 제공한다. 분명하게 이 기술
은 개발자들에게 데이터베이 스 안에서 내장 프로시저를 사용하도록 허용한다 FGAC 기능은 데이터베
이스에 쿼리를 실행할 때 쿼리를 바로 수정할 수 있도록 하는 기능이다. 이 쿼리 수정은 고객이 받거나
수정할 로우를 제한하는 데 사용된다. 그 프로시저는 누가 쿼리를 수행하는지, 언제 쿼리를 수행하는
지, 어떤 애플리케이션이 데이터 를 요청하는지, 어떤 터미널에서 쿼리를 돌리는지 등을 볼 수 있다. 그
리고 데이터에 접근하는 것을 적절히 제한할 수 있다 FGAC를 가지고 아래의 예와 같은 보완책을 강
제할수있다.
• 정상적인 업무 시간 외의 시간에 특정 권한을 가진 사용자에 의해 실행된 쿼리는 아무 결과를 응답
하지않는다.
• 모든 데이터는 보완 장치가 있는 터미널에 응답될 수 있고 원격 클라이언트 터미널에는 민감하지
않은 정보만 응답될 수 있다.
기본적으로 FGAC는 데이터베이 스 즉 바로 데이터 안에서 우리 에게 접근 제어를 하도록 허용한다. 사
용자가 자바 빈이나 JPS , ODBC를 시용하는 비주얼 베이직 또는 SQL*PLUS에서 왔는지의 여부는 더
이상 중요하지 않다. 어느 것이든 통일한 보완 프로토콜이 강제될 것이다. 여러분은 다음 세대의 기 술
을 배울좋은자리에 있는것이다.
이제 어떤 구현이 더 개방적인지 질문을 던지려 한다. 하나는 비주얼 베이직 코드와 ActiveX 컨트롤을
호출해야만 데이터에 접근할 수 있다(원한다면 비주얼 베이직 대신 자바 빈 ActiveX 대신 EJB로 바꾸어도 된
다. 필지는 단지 특정 기술이 아니라 구현 방법에 대해 다루는 것이다) . 또 다른 하나는 다%탤 SSL, HπP ,
Oracle Net이나 ODBC, JOBC, OCI와 같은 API를 사용하는 등 데이터베이스에 질의를 던질 수 있는
모든 것에 대해 접근을 허용하는 것이다. 필자는 아직까지 비주얼 베이직 코드를 쿼리하는 직접적인 레
포팅 도구를 본 일이 없다. 그렇지만 SQL을 통해 할 수 있는 것은 많이 알고 있다.
데이터베이스 독립과 완전한 개방성을 위해 노력하려는 결정은 사람들이 완전하게 자유롭게 가지는 것
이며, 많이 시도하는 것이다. 그러나 필자는 그것이 잘못된 결정 이라고 믿는다. 어떤 데이터베이 스를
사용하든 간에 그 제품으로부터 나올 수 있는 기능 마지막 하나까지 짜내면서 완벽하게 이용해야 한다.
결론적으로, 여러분은 개발과 실 제 운영 환경에 적용한 후 반드시 겪게 되는 튜닝 단계에서 그렇게 해
야 할 것이다 데이터베이 스 독립성 요구사항을 만족하게 하는 것보다 데이터베이 스의 기능들을 잘 사
용해서 애플리케이션을 원래보다 5배는 빠르게 수행하도록 만들면, 데이터베이스 독립성 요구사항을
쉽게 포기할 수 있을 것이다
62
• • • CHAPTER 01 성공적인 오라클 애를리케이션 개발
애플리케이션 실행 속도를 빠르게 하는 방법
위 제목과 같은 질문을 항상 듣는다. ‘데이터베이 스 튜닝’ 이 데이터베이 스를 조정하는 것을 의미하듯
모든 사람들은 ‘ 빠른 것=옳은 것’ 이라는 진리를 갈구한다. 사실 80%(종종 100%) 이상의 성능 향상은
데이터베이 스 레벨이 아니라 애플리케 이션 설계와 구현 레벨에서 실현된다. 데이터베이 스 안에서 구동
하는 애플라케이션을 튜닝하기 전까지 데이터베이 스를 튜닝할 수 없다.
시간이 지남에 따라 데이터베이스 례벨에서 심각한 프로그래밍 실수를 줄여줄 수 있는 몇 가지 장치가
추가되었다. 오라클 816에는 CURSOR_SHARING = FORCE 라는 새로운 파라마터가 추가됐다. 이
가능은 auto binder를 구현한다 SELECT * FROM EMP WHERE EMPNO=1234처럼 쓰인 쿼리를
조용히 가져다가 SELECT * FROM EMP WHERE EMPNO =:x처럼 바꾸어 준다. 이 기능은 하드 파
스를 극적으로 줄여줄 수 있으며 아키텍처 절에서 논의했던 라이브러리 래치를 줄여준다. 그러나 몇
가지 부작용이 었다. 커서 공유 때문에 발생하는일반적인부작용은다음과같다.
ops$tkyte없RA11GR2> select /* TAG */ substr( username, 1, 1 )
2 from all users au1
3 where rownum = 1;
S
S
ops$tkyte%ORA11GR2> alter session set curso仁sharing=force;
Session altered.
ops$tkyte%ORA11GR2> select /* TAG */ substr( username, 1, 1 )
2 from all users au2
3 where rownum = 1;
SUBSTR(USER뻐ME , 1 , 1)
S
무슨 일 이 일어난 것일까? 왜 SQL*Plus에서 본 컬럼 이 두 번째 실행한 쿼리에서 커졌을까? 서 로 같은
쿼리라고 주장할 수 있는가? 만일 커서 공유 설정 때문에 일 어난 일이라고 가정한다면, 다음의 사실이
분명해질것 이다.
ops$tkyte%ORA11GR2> select sql_text from v$sql where sql_text like 'select /* TAG */ %';
SQL TEXT
63
전문가를 위한 오라클 데이터베이스 아키럭처 • • •
select 1* TAG *1 substr( username, 1, 1) f rom all_users au1 빼e re rownum =
select 1* TAG * 1 substr( username, : "SYS_B_0 ", : "SYS_B_1" from all_users
au2 빼ere rownum = : "SYS 8 2"
커서 공유는 쿼리에서 정보를 제거한다. 커서 공유는 우리가 사용하고 있는 Substr 함수에서 사용한 상
수를 포함하여 모든 문자열을 찾는다 모든 쿼랴에 대입된 상수들을 제거하고, 바인드 변수로 비꾼다
SQL 엔진은 해당 컬럼이 1 의 길이를 가진 substr이라는 것을 알지 못한다. 물론 그 길 이는 정확히 알
수도 없다 rownum = l 도 바인드 변수로 바꾸어야 할 대상인 것을 알 수 있다. 매우 효과적인 방법처
럼 보인다. 그러나 옵티마이저는 방금 몇 가지 중요한 정보를 제거해버렸다 더 이상 ‘이 쿼리가 한 개
의 로우를추출한다’는 것을얄수 없게 되었다. ‘이 쿼리는 이제 처음 N 개의 로우를응답하고, 그것이
몇 개인지는 알 수 없다’ 이것은 여러분이 만든 쿼리의 플랜에 부정적인 영향을 미칠 수 있다
게다가, 이미 알아본 것처럼 CURSOR_SHARING= FORCE를 설정하는 것이 많은 하드 코딩된 쿼리
를 파싱하고 최적화하는 것보다 훨씬 빠르게 수행하는 반면 개발자가 바인드 변수를 사용하여 개발한
쿼리를 시용하는 것보다는 느리다는 것을 발견했다 커서 공유 코드의 비효율성 때문에 생기는 것이 아
니라 프로그램 자체의 비효율성 때문에 발생하는 것이다 많은 경우에 있어 바인드 변수를 사용하지 않
은 애플리케이션은 효율적으로 파싱하거나 커서 를 재시용하지 않는다. 애플리케이션은 모든 쿼리가 유
일하다고(하드 코딩되었다괴 판단하기 때문에 커서를 한 번 이상 절대로 사용할 수 없다 사실 개발자가
처음부터 바인드 변수를 사용하였다면 오라클은 쿼리를 한 번만 파싱하고 여러 번 재사용했을 것이다.
이것이 전체적인 성능을 하락시키 는 파싱의 간접 비용이다.
CURSOR SHARING=FORCE 기능을 켜는 것만으로 여러분의 문제를 반드시 고칠 수 있는 것은 아
니라는 사실을 꼭 기 억하자. 오히려 새로운 문제를 일으킬 수도 있다 CURSOR_SHARING은 어떤
경우에는 매우 유용한 도구지만 만병통치약은 아닌 것 이다. 잘 개발된 애플라케이션은 이 기능을 필요
로 하지 않는다. 결국, 바인드 변수를 적절한 곳에 사용하고, 상수를 필요한 것에 사용하여 개발하는 것
이 올바른 방법이다,
I Note I 만병통치약은 없다 절대로! 만일 있다면 그것은 기본적으로 제공되는 동작일 것이며, 여러분은 그것에 대해 결코
듣지못할것이다
데이 터베이스 레벨에서 얻을 수 있는 몇 가지 옴션들이 있긴 하지만 많지는 않는다. 동시성 문제와 관
련된 문제와 잘못 개발하고 잘못된 구조를 가진 데이터 때문에 발생하는 수행 성능이 떨어지는 쿼리들
64
.. .. .. CHAPTER 01 성공적인 오라클 애플러케이선 개발
을 고치는 지름길은 없다. 이런 상황에서는 재개발이 필요하고 종종 아카텍처를 재설계할 펼요가 있기
도 하다. 데이터 파일을 이동하는 것 파라미터들을 조정하는 것, 그리고 다른 데이터베이스 레벨의 스
위치들은 애플리케이션의 전반적인 성능에 사소한 문제를 자주 일으킨다. 그 정도 조치로 애플라케이
션을 납품하기 위해 요구되는 2 배 3배 혹은 N배의 성능 향상을 가져오지는 않는다. 애플라케이션이
10% 느려지는 일이 얼마나 자주 일어나는 일일까? 10% 느려졌다고 해서 아무도 그것에 대해 문제를
제기하지는 않는다. 그렇지만 5 배 느려진 경우라면 사람들은 마음이 상할 것이다. 반복해서 말하면, 여
러분은 ‘데이터 파일을사방으로옮기는 것’으로는 5배의 성능향상을 얻을수 없을 것이다. 차라리 아
마도 1/ 0를 크게 줄이는 작엽처럼 애플리케이션을 고치는 것을 통해서만 큰 성능 향상을 이룰 수 있을
것이다.
I Note I 우|의 사실은 어떤 일들을 해야 시간이 오래 걸리는 것을 고칠 수 있는지 말하는 것이다 띨자는 여러분이 데이터
파일을 사방으로 옮기는 것으로는 5배의 성능 항상을 얻을 수 없을 것이라고 자주 써왔다 데이터베이스를 확~하도록 설계
된 저장 영역 네트워크 장치인 오라클 Exadata와 같은 하드웨어 솔루션의 등장으로 사실 여러분은 데이터 파일을 사방으
로 단순히 옮기는 것으로는 응답 시간을 5 배 10배 50배 또는 그 이상 줄일 수 있었다 ‘스토리지를 재구성하자 라는 이야
기라기보다 ‘하드웨어 아키텍처를 완전히 변경하자’ 는 이야기다
성능은 설계의 중요한 목표며 구축하고 개발 단계를 걸쳐 계속 태스트해야 할 것이다. 이것은 결코 나
중에 생각해야 할 무엇인가가 아니다. 필자는 사람들이 애플리케이션을 고객에게 출하하기까지 대기하
고, 설치하고, 심지어 튜닝도 하지 않고 실제로 운영한다는 사실에 자주 놀란다. 펼자는 다른 인텍스는
말할 것도 없고, 기본 커조차 없이 납품되는 애플라케이션도 자주 보았다. 쿼리는 한 번도 튜닝된 적이
없거나 부하 테스트를 한 일도 없다. 그 애플라케이션은 몇 명의 사람에 대해서조차 테스트해본 일이
없었다. 튜닝은 제품 설치의 일부분으로 생각된다. 필자는 이러한 방식을 도저히 용납할 수 없다. 여러
분의 고객에게 처음부터 잘 응답하고 충분히 튜닝된 시스템을 제공해야 한다. 고객이 처음 접하는 성능
문제를 제외하고도 다루어야 충분한 제품의 문제들이 있을 것이다. 고객들은 새로운 애플라케이션에서
몇 개의 버그가 있을 것이라고는 생각하지만 최소한 고객들이 그런 버그가 화변에 나타나기까지 고통
스러울 정도로 긴 시간 동안 기다리게 해서는 안 된다.
DBA와 개발자와의 관계
가장 성공적인 정보 시스탱은 DBA와 애플리케이션 개발자 간에 협력 관계에 근거해서 만틀어진다는
것은 분명한 사실이다. 이 절에서 필자는 개발자와 DBA 사이의 구분된 일들에 대해 개발자의 관점에
서 보여주고 싶다(모든 중요한 개발에는 DBA 팀이 있다고 가정한다).
개발자로서 여 러분은 소프트웨어를 설치하고 환경을 설정할 필요는 없을 수도 있다. 그것은 DBA의 역
할이며, 아마도 ‘시스템 관리자 (System Admi뼈
65
전문가률 위한 오라클 데이터베이스 아키텍처 • •
리스너를 띄우고, 공유 서버를 설정하고, 커넥션 풀을 만들고, 데이터베이스를 설치하고, 데이터베이스
를 생성하는 등의 일은 DBA /SA가 해야 할 일들이다.
일반적으로, 개발지들은 운영체제를 어떻게 튜닝해야 하는지 알 필요가 없을 것이다. 필자는 이런 종류
의 일들은 시스템 담당자들에게 맡긴다. 데이터베이스 소프트웨어 개발자로서 여러분은 운영체제를 능
숙하게사용할필요는있지만 그것은튜냥해야할필요는없을것이다.
DBA의 가장 큰 책임은 데이터베이스 복구다. ‘백업’ 이 아니라 ‘복구’ 라고 말한 점에 주의하자. 난 이
것이 DBA 의 유일한 책임이라 강조하고 싶다. 롤백과 리두 작업의 이해 정도는 개발자들이 알아야 할
것이다. 테이블스페이스 (tablespace) 의 시점 복구 방법은 개발자들이 알기 어려운 것이다. 그 방법을 아
는것이 여러분에게쓸모가있고 실제그런작업을해야하는것은아니다
데이터베이스 인스턴스 레벨을 튜냥하고 최적화된 PGA_AGGREGATE_TARGET이 무엇인지 찾는
것은 DBA들의 일반적인 일이다(데이터베이스는바른설정값을결정하기 쉽게 되어 있다). 개발자즉들이 세션
에 관련된 몇 가지 설정을 바꾸는 일은 예외적인 경우다. 데이터베이스 레벨에서 DBA가 해야 할 일이
다. 일반적인 데이터베이스는 한 명의 개발자의 애플리케이션 이상을 제공한다. 모든 애플리케이션을
지원해주는 DBA만이 바른결정을내릴수있다.
공간을 할당하고 파일을 다루는 일은 DBA가 할 일이다. 개발지들은 자기들이 필요하다고 느끼는 크기
만큼의 공간에 대해서만 의견을 말할 것이다 DBA나 시스템 관리자는 나머지 부분도 신경 써야 한다
가본적으로, 개발자들은 데이터베이스를 어떻게 실행시카는지 알 필요가 없다. 데이터베이스 안에서
프로그램을 실행시키는 방법만 알면 된다. 개발지들과 DBA는 같은 퍼 즐의 다른 조각들에서 같이 일하
는 것과 같다 DBA는 개발자들을 방문하고 개발자들은 자기가 만든 쿼리가 너무 많은 자원을 소비할
때 DBA를 찾고, 어떻게 시스뱀을 더 빠르게 처리할 수 있는지 방법을 찾을 것이다(이것은 인스턴스 튜
닝이 이루어지고, 애플리케이션이 충분히 튜닝되면 된다)
이런 점은 상황에 따라 모두 다양하겠지만, 분명히 구분이 있다고 생각하고 싶다. 좋은 개발자는 일반
적으로 DBA로서는 나쁘며 그 반대도 사실이다. 내 생각에 그들은 두 개의 다른 기술을 가지고 있고
두 개의 다른 마음을 갖고 있고 두 개의 다른 개성을 갖고 있다.
정리
1 장에서는 왜 데이터베이스를 알아야 하는지 간단한 예를 들어서 살펴보았다. 펼자가 제시한 샘플들은
매일 밤낮으로 발생하는 것으로 현실과 동떨어진 것들이 아니다. 그런 문제들이 계속 반복해서 발생하
는 것을 많이 접하고 있다.
66
I
• • • CHAPTER 01 성공적인 오라클 애를리케이션 개발
정리해보자. 만일 여러분이 오라클로 개발을하고 있다면 다음사항들을 기억하자.
• 오라클 아카텍처에 대해 이해해야 한다 서버를 재개발할 정도의 깊은 지식을 알 필요는 없지만,
특정한기능을활용하려고할때 그와관련되어 있는지식에 대해서는충분히 알아야한다.
• 락과 동시성을 이해해야 하며, 각각의 데이터베이스는 이러한 기능을 각각 다른 방법으로 구현하
고 있다는 점을 이해해야 한다. 여러분이 이 점을 이해하지 못한다면 데이터베이스에서 잘못된 결
과물을 얻게 될 것이며, 커다란 문제점을 안게 될 것이며, 좋은 성능을 이끌어 낼 수 없을 것이다.
• 데이터베이스를 이해할 필요가 없는 블랙박스처럼 다루지 마라. 데이터베이스는 대부분의 애플라
케이션 중에 가장 중요한 부분이다. 데이터베이스를 무시하면 치명적인 결괴를 얻게 될 것이다.
• 시간을 허비하지 마라. 데이터베이스가 기본적으로 제공하는 기능을 알지 못히는 것 때문에 기술
적인 레벨뿐 아니라 개인적인 레벨에서 어려움을 겪는 팀을 많이 보아왔다. 개발팀이 몇 개월 동안
구현하려고 시간을 허비한 기능틀이 사실은 데이터베이스가 오랫동안 가지고 있던 핵심 기능이었
다는 점을 지적하면 크게 실망하는 것을 자주 본다. 오라클 데이터베이스 기초 안내서, 새로운 기
능 안내서, 소프트웨어를 구입할 때 같이 제공되는 문서를 읽기 바란다.
• 문제를 되도록이면 간단한 방법으로 해결하랴. 대부분은 오라클이 기본적으로 제공하는 함수를 사
용하여 해결할 수 있다. 데이터베이스를 사용하기 위해 여러분은 충분히 많은 돈을 지불하였으니
사용할 권리는 여러분에게 있는 것이다.
• 소프트웨어 개발 프로젝트들은 여러 프로그램 언어와 프레임워크가 그런 것처럼 생겼다 없어졌다
한다. 우리 개발지들은 몇 주 또는 몇 달 동안 시스템을 구축한 후 또 다른 문제를 만나게 된다. 만
일 여러분이 계속 시간을 허비한다면, 정신 없이 진행되는 개발 일정을 결코 맞출 수 없게 될 것이
다 여러분이 자바로 개발할 때 자바가 기본적으로 제공하는 기능인 해시 테이블 클래스를 직접 만
들지 않는 것처럼, 여러분이 원하는 대로 사용할 수 있는 데이터베이스 기능을 사용해야 한다. 물
론, 이런 일을하려면 먼저 당신이 원하는기능이 무엇인지 이해해야한다.
마지막으로, 소프트웨어 프로젝트와 프로그램 언어는 생겼다 없어졌다 할 수 있지만, 데이터는 영원히
존재한다. 우리는 데이터를 이용하는 애플리케이션을 만들고, 이 데이터는 많은 애플라케이션에서 계
속해서 사용될 것이다. 애플리케이션보다 데이터가 중요하다. 데이터가 계속 사용되고 재사용될 수 있
도록 여러 기술들과 방법을 시용하라. 여러분야 데이터베이스를 양동이처럼 시용하고, 모든 데이터에
대한 접근이 여러분이 만든 애플리케이션을 통해서만 가능하도록 만든다면, 여러분은 요점을 잃은 것
이다 여러분은 애플리케이션에 비정형 쿼리를 사용할 수 없다. 여러분은 이전의 낡은 애플리케이션 위
에 새로운 애플리케이션을 구축할 수 없다. 그러나 여러분이 데이터베이스를 이용한다면 새로운 애풀
리케이션을 추가하고, 리포트를 추가하는 등의 일을 이전보다 훨씬 더 쉽게 만들 수 있을 것이다.