JPA에서 별도의 모니터링 툴 구축없이 정확한 쿼리 추출이 가능한 방법이 있을까요?

2015-12-25 08:59

안녕하세요. 사내에서 일부 프로젝트에 JPA를 사용중에 있습니다.

JPA 사용이후 쿼리 변환에 대한 질문 드립니다.

회사내에 업무 및 배포 프로세스상 개발 및 QA 완료 이후에 보안검수, 쿼리검수, 기타 검수과정이 포함되어서 진행됩니다. JPA를 사용하게 되면 이후 쿼리검수 양식에 맞춰서 쿼리 추출후 전달이 필요한데 JPA에 생성된 쿼리를 로그에 출력하게 되면 실제 모델에 기술한 쿼리가 아닌 임의로 변환된 쿼리로 출력됩니다.

ex) Domain : User (Entity :tbl_user)
- String userName, - String nickName - String address - Date createDate

ex) 주소로 회원의 정보 검색시 JPA에서 생성된 쿼리

select user0_.id as id1_1_, user0_.address as address2_1_, user0_.create_date as create_d3_1_, user0_.nick_name as nick_nam4_1_, user0_.user_name as user_nam5_1_ from tbl_user user0_ where user0_.address=?

개발과정에선 쿼리의 반복적인 작업에서 벗어났지만 개발 완료후 쿼리검수를 위해 TABLE상에서 사용하는 칼럼 값 기준으로 위의 쿼리를 재수정하는 번거로움이 일부 있었습니다.

pinpoint나 기타 별도의 모니터링 툴 구축없이 정확한 쿼리 추출이 가능한 방법이 있을까요.?

5개의 의견 from SLiPP

2015-12-15 18:03

@김형석 저도 이와 관련한 투렷한 해결책은 잘 모르겠어요. DBA와 협의만 잘 되면 좋겠지만 그렇지 않은 경우가 대부분인지라.

저는 기존 회사에서 DBA와 친분을 맺은 후 ORM에 대해 설명하고 쿼리 변환없이 JPA가 생성하는 쿼리를 전달함으로써 쿼리 검수를 진행했어요. DBA가 그리 좋아하지는 않았을 수도 있었겠지만 저희 개발팀의 고충을 이야기해서 풀어가는 방식으로 접근했어요.

자동으로 생성되는 쿼리를 table 칼럼 기반으로 변경하는 부분은 검색해도 나오지 않네요.

2016-01-07 01:31

예전에 함께 일했던 시니어가 알려준 방법이 있었는데요

요구사항의 발단은

  • APM류를 사용하지 않고 SlowQuery를 잡아낼 수 있는 방법 (Query Execution Threshold를 통해 해당 Threshold를 초과하면 ErrorLog로 출력 )
  • 쿼리별로 평균 수행시간, 호출빈도, 가장 오래 수행된 시간 등.. (DBA에게 쿼리 검수를 받거나, 쿼리 분석을 위해)
  • DEBUG 모드 일때 콘솔을 통해 포맷팅된 쿼리 보기 ( Hibernate의 show_sql 옵션은 포맷팅이 아름답지 않아서, 또한 파라미터가 전부 바인딩되서 복붙후에 DB 툴에서 바로 실행 할 수 있는 형태의 쿼리 )

이런 요구사항들로 부터 출발했었고, 해결방법은 Proxy를 이용해서 심플하게 구현했었습니다.

  • Connection Pooling 라이브러리 선정 ( 저는 당시 DBCP2를 사용하다가 HikariCP로 넘어 갔었습니다 )
  • Connection Pooling 라이브러리의 DataSource를 상속받아 Proxy객체를 끼워넣는다.
  • DBCP의 경우 BasicDataSource를 상속받았고,

@Override
public Connection getConnection(String user, String pass) throws SQLException {
    Connection connection = super.getConnection(user, pass);
    return createProxy(connection);
}
private Connection createProxy(Connection originalConnection) {
    ProxyFactory proxyFactory = new ProxyFactory();
    proxyFactory.setTarget(originalConnection);
    proxyFactory.addAdvice(new CreateStatementInterceptor(getDataSourceId(), getDatabaseType(), getQueryTimeout(), getSlowQueryTime(), isUseSqlLogFormat(),
            statementInfoMap, sqlTaskPool));
    proxyFactory.setInterfaces(new Class[]{Connection.class});
    return (Connection) proxyFactory.getProxy();
}

과 같은 방식으로 Connection 객체를 반환할때 Proxy로 한번 감싸주었습니다.

이렇게되면 ORM (JPA/Hibernate), SQL Mapper(MyBatis..), JOOQ, QueryDSL등 어떠한 라이브러리를 사용하더라도 JDBC Layer를 모두 통과하게 되어 있다보니 SlowQuery, Query Logging (Formatting), Query 통계 등을 편리하게 뽑아 낼 수 있었습니다. (물론 쿼리를 이쁘게 포맷팅해주는 유틸, Map에 쿼리들을 Key,Value로 분류해 카운팅 하는 부가적인 기능들은 직접 개발했었습니다)

이부분에 추가로 형석님이 원하시는 기능 (Hibernate 쿼리를 사람이 보기 편한 쿼리로 변환)을 HibernateQuery Normalizer등으로 이름짓고 끼워넣으시면 DBA에게 쿼리를 줄때 매번 변환하지 않아도 될 것 같습니다.

재미있을 것 같네요. 저도 예제 소스로 간단히 정리되는대로 Github에 공유를 한번 해보도록 하겠습니다!

의견 추가하기

연관태그

← 목록으로