Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

관계형 데이터베이스의 종류는 많으며, SQL문을 빠르게 작동시키기위해 DB엔진은 구문분석후

효과적인 결과를 내기위해 실행계획을 세우게 되며 이것은 각각의 데이터베이스마다  풀스캔/인덱스스캔등의 차이에 따라서도 다른 실행계획이 나옵니다차이가있습니다.

SQL문에서 이러한 실행계획을 직접 조정할수 없을뿐더러, 전적으로 DataBase에게 위임하게 됩니다. 

즉, JPA도 이러한 실행계획에 관여할수 없으며 이러한 실행계획을 확인하는 방법은 SQL문을 실제

실행하여 어떻게 작동되는지 확인하는것입니다.

이름명령어
Oracleset autotrace traceonly
MSSQLSET SHOWPLAN_TEXT_ON
DB2EXPLAIN ALL WITH SNAPSHOT FOR SQL 구문
PostreSQLEXPAIN SQL 구문
MySQLEXPLAIN EXTENDED SQL 구문

...

보여주는 예입니다. 반환타잎은 Java오브젝트뿐만아니라,웹에서 바로 사용가능한 Json 결과로 뿌려줄수 있기떄문에

JPA에서  사용코드내에서 사용자정보에서 학생정보만 추출하는 과정이 이 한줄이외에 더 추가되는것은 JPA에서

개발 생산성 낭비로 측정하고 있습니다.  하지만 SQL문을 직접 작성하지 않을뿐

이러한 JPA 인터페이스가 어떤 SQL문으로 변환되어 실행이 되고 실제 데이터베이스에서

실행계획이 어떻게 되는지 점검할 되는지점검할 필요가 있습니다.


JPA문이  실제 어떠한 SQL문을 실행할지 예측할수도 있지만, 아래 옵션을 켜서 실제 SQL문 확인가능합니다.

...

어플리케이션의 JPA테스트코드와 SQL 실행을 Trace한 예

쿼리실행을 JPA를 통해 간단하게 할수 있기때문에 , 데이터베이스를 조회하고 변경하는 코드에대해 JPA를 통해 작성된 인테페이스를 통해 어플리케이션에서 작동되는 실제 쿼리를 수행을 간단하게 할수가 있으며

어플리케이션 레벨에서 쿼리에관련된 TestCase 작성을 쉽게하고 또한 실제 작동되는 SQL문도 체크할수 있습니다.

이것은 유닛테스트 작성에 시간을 줄여,  SQL/SP에는 코드변경점이 많아 시도해볼수 없는

많을것들을 할수 있게하며, 궁극적으로 어플리케이션에서 DB 호출 최적화를 할수 있는 여유시간을 가질수가 있습니다.

대부분의 성능문제는 쿼리 자체 최적화문제가 아닌, 어플리케이션이 불필요하게  많은 쿼리를 호출하는데 발생합니다.

물론 실행계획까지 개발툴에 통합되어 포함되었으면 하는 바램도 있습니다. 반복작업에 드는 개발시간을 최대한 줄이고, 유닛테스트를 활용하는데 전환할수가 있습니다.




실행계획 조사하기

실행계획의 출력포맺은 DB마다 다르지만 공통적인 3가지요소가 있습니다.

...

적은량의 데이터에서 탐색시 효과가 없을수 있으나,  데이터량이 늘어남에따라 효과를볼수가 있습니다.


프로그래밍 모델에서 간단하게

List<String>  VS  BTree<Key>  VS Map<int> 

위 세가지 자료 구조의 접근 차이 라고 보면 될듯합니다. 

List는 순차 풀스캔, BTree사용의 경우 이진트리탐색 , Map 의경우 해시를 통한 탐색


스캔 범위/방식에따른 실행계획 전략

성능을 위한 스캔 범위 Type은 3가지정도로 요약할수 있습니다.

  • 이중루프(Nested Loops) : 한쪽테이블을 읽으면서 결합조건에 맞는 레코드를 다른쪽에서 찾음
  • Sort Merge : 결합할 두 테이블을 정렬을 하고 순차적으로 결합
  • Hash : 결합 키값을 해시로 맵핑, 엑세스 횟수를 줄이고 약간비용이드는 랜덤 접근

스캔범위및 실행 계획이 복잡해지지 않게 하기 위해서 말은쉽지만 어려운 방법 두가지입니다위한 가장 간단한 규칙이지만,

우리가 원하는 집합을 만들다보면 이 규칙을 깨트리기 쉽고, 쿼리능력자에따라 차이가 날수있습니다.

  • 스캔 범위 줄이기
  • 조인을 덜 복잡하게 만들기

참고 : https://community.modeanalytics.com/sql/tutorial/sql-performance-tuning/

루프중에도 양쪽풀스캔을(A X B) 랜덤스캔 방식으로 하는 케이스가 성능적으로 가장 나쁜 케이스라고 보시면되며

조인이 복잡하면 절차형 프로그래밍에서 이야기하는 루프의 형태를 예측하기가 어렵습니다.

Image Removed



참조해야할 테이블수가 늘어남에따라 조인의 복잡도를 감소시켜, 우리가 원하는 집합을 만들기란 어려운일중의 하나이며만들기위해, 아래와같은 조인문과 2개의 테이블만 조작하면 좋겠지만

실제는 그렇지 않습니다. 

Image Added특히나 쿼리문만보고 실행계획을 예측한다란것은 거의 불가능에 가깝습니다.

권한 이양의 죄악

이러한 이와같은 실행계획 개입은, SQL문을 통해 할수있는게 아니고, 권한은,SQL문에서 할수 있는게 아니고  RDB에 모든것을 이양해야하고

실제 작동을 시켜 실행계획을 파악해야한다는것입니다. 테이블 설계가 동일하다고 가정했을시

코드가 길어도 실행계획이 띄어난 SQL문 VS 간결한 SQL문, 두가지 SQL문이 있다고 하면

전자를 만들수 있는 SQL개발자가 더 뛰어난 개발자로 분류하였습니다.

하지만 시간이흘러 다음 데이터베이스에서는 어떠한 SQL문의 실행계획이 뛰어날지 혹은?

데이터량이 늘어나는순간 실행계획이 바뀌게 될지 예측하기가 어렵습니다.

일반적으로 실행계획에 최악이 아닌 방식을 택할수 있지만,

우리는 단지, 실행계획에 최적화된 SQL문 작성을 위해 노력해야한다는것입니다.

최적화된 실행계획이, 데이터의 변화에 따라 최악으로 변경될수 있다란점도 인지해야하며

최상의 쿼리는, 실행계획이 변하지않는 적당수준의 느린 쿼리문이 될수도 있습니다항상 최선인 방식을 택하고 또한 그것이 성능적으로  항상 뛰어난 SQL문이다라고 정의내리기는 어렵습니다.

JAP를 통한 튜닝 포인트의 발상변화

JPA에서는 실행계획이 틀어지고, 예측하기 어려운 튜닝포인트를 쿼리중심에서

OOP중심, 즉 어플리케이션서 관여할수 있는 계층을 한더 하나더 추가하였습니다.

JPA PROXY/영속성 전이등을 사용하여, 어플리케이션 자체에서

DB접근을 최소화하는 전략을 택할수 있으며...


가장 간단하게 사용될수 있는방법은설명을하면....

User user1 = findByName("Minsu");

User user2 = findByName("Minsu");

user1.GetName()

user2.GetName()

JPA에서는 기본적으로, 동일 트랙잰션에서 위와같은 동일처리에대해서동일처리라고 판단되는 사항에대해

SELECT SQL한번만 조회를하고, 두번째는 DB 호출없이 오브젝트 재사용을 합니다재사용전략을 택합니다.

기존에는 이러한 코드는 SQL을 직접호출하는 함수에서는 SELECT SQL을 두번 모두 호출하였을것입니다.

물론 JPA에서 지연로딩같은 특수한 기능은 중복호출실수를 잡아주는 기능은 아니며

오히려 정확한 의미를 파악한후 사용을 해야합니다.


Read전략:

  • 즉시읽기( Eager loading) : 
  • 지연읽기 ( Lazy loading ) :

...

JPA를 분명 객체지향과 데이터모델링 사이에 간극을 최소화하고 편리한 방식임에는 분명하지만

객체지향관점으로 DB병목이없는 성능좋은  어플리케이션을 만들기위해서튜닝 관점을 쿼리에서 JPA에서 제공하는 레이어활용으로 전환을 하려면

중간에 새로 생긴 계층을 잘 활용해야하며계층뿐 아니라,  더 많은 DB병행 학습 필요하다란 것입니다.  

이것은 관계형DB와 객체지향의 불일치를 맞추려고 노력하는 시간보다 분명 더 값어치 있는 시간으로 보여집니다시간이 의미 있는 시간으로 전환될지?

의미 없는 더 많은 시간을 소모하게될지? 

활용도와 역량에 의존성이 있기 때문에 예측하기는 쉽지 않습니다.



참고: http://zzong.net/post/15