key를 ident 값으로 주는게 있었고, 양쪽 테이블을 동일하게 맞춰났다. 하지만 프로시저에서 로직 오류가 있어서 사용하다 보니 어느 순간 두 테이블의 ident 값이 틀어져 있었고, key값으로 비교 시 이상하게 비교가 되었다.

필요: dbcc checkident(테이블명, noreseed) 는 현재 테이블의 ident 값을 가져오는 것이지만 if문에서 양쪽 값 비교 필요

해결: select IDENT_CURRENT(테이블명) 으로 하면 현재 테이블의 ident 값을 select로 가져올 수 있음

Posted by 知彼知己百戰不殆
,

데이터 양이 매우 많은 테이블들이 여러개 조인되고 그 안에서 조건을 넣어 조인을 하다 보면 SQL 속도가 상당히 느려짐.

이 때 임시 테이블이나 신규로 통계 데이터를 저장하는 테이블을 만들어서 작업 외 시간에 해당 테이블에 저장을 미리 시킨 후 해당 쿼리 결과가 필요할 땐 신규 테이블에서 값을 가져와서 보여주는 형태로 하면 빠름.

단점 : 실시간 확인해야 하는 통계 SQL에는 적용하기 힘듦. 이 땐 SQL 튜닝이나 다른 방법을 찾아야 함

Posted by 知彼知己百戰不殆
,

오류 상황 : mybatis 도입 후 테스트 프로젝트에서는 문제 없이 작동했던 부분이 원본 프로젝트 소스와 merge 하고 나니 오류 발생. 1, 2, 3, 4 쿼리를 순차적으로 타고 결과를 도출해야 하는데 1번 쿼리 실행 후 catch문 로그도 안 찍고 갑자기 finally로 빠져버림.

트러블슈팅 : ① 오류 로그라도 뭔가 확인이 가능해야 버그를 잡아내는데 아무런 로그가 안찍히니 답답했다. 그래서 할 수 없이 디버깅 모드로 실행 후 오류나기 바로 전 메소드에 toggle 걸어주고 한 step씩 넘기면서 모든 변수 값 다 확인.
② log4j 관련 변수였나? 정확한 기억은 안나지만 특정 변수에 java.lang.NoSuchMethodError: org.apache.log4j.Logger.isTraceEnabled()Z 오류 내용이 들어감
③ 지난 번 테스트 프로젝트에서 보고 해결했으나 블로그에 안 적어놔서 다시 구글링
④ log4j 1.2.12 버전 이후로 해당 메소드가 들어가 있다는 내용 확인
⑤ log4j.jar 파일 교체(기존: 1.2.8 버전)

하지만 아직도 왜 catch문을 안 탔는지 이해가 잘 안 간다. 추후 좀 더 확인해볼 필요가 있음.

Posted by 知彼知己百戰不殆
,

Table A (group by 한 값들이 모두 들어있는 테이블)
select '1' from dual union all
select '2' from dual union all
select '3' from dual union all
select '4' from dual union all

Table B (실제 값 가져오는 쿼리)

이런 식으로 group by 했을 때 무조건 나와서 통계 표와 맞춰야 하는 값들 강제 작성 후 left join 

Posted by 知彼知己百戰不殆
,

오류 상황 : 쿼리 실행 시 String 값 하나만 넘기면 되는데 굳이 vo를 생성해서 넘기기도 귀찮아서 String 파라미터를 넘기는데 계속 로그에 parameters : null이 찍힘

원인 : Dao쪽을 살펴보니 selectList(statement , object )가 아니라 selectList(statement)를 호출 중

해결 : selectList(statement , object)로 Dao 메소드 변경

Posted by 知彼知己百戰不殆
,

변동값을 group by 하는 tip

예를 들어 각 나이대별 00 건수 데이터를 뽑고 싶을 때

구분 5년이상 10년이하 10년이상 15년이하 15년이상 20년이하 ~~~
20세 ~ 30세        
30세 ~ 40세        
40세~ 80세        
         

위와 같은 표의 데이터를 뽑을 때 처음에 어떻게 데이터를 뽑아야 할지 머리가 안 돌아갔다.
구분값이 다 변동값인데 이걸 어떻게 group by로 뽑아내지 하다가 문득 든 생각 

20세와 30세를 그룹으로 묶고 30세~40세를 그룹으로 묶어 버리자.

그래서 gruop by를 하기 전 case when 컬럼1 between 20 and 30 then '1'
when 컬럼1 between 30 and 40 then '2' 
...

이런 방식으로 그룹핑을 지어주었다. 그리고 또한 기간도 case when 컬럼2 between 5년 between 10년 then '1'
when 컬럼2 between 10년 and 15년 then '2'

이렇게 변동값을 그룹으로 한정해버리고 쿼리 추출!!

쿼리는 항상 너무 어렵다 ㅠㅠ

Posted by 知彼知己百戰不殆
,

왜 프레임워크를 안 쓰는지 모르겠으나 ㅠㅠ 쌩 java로만 돌리는 환경.
대량 조회 하는 SQL을 thread까지 사용해서 동시에 돌리니 기존에 잘 돌아가던 쿼리도 executeQuery 부분에서 OutOfMemory가 발생함ㅠㅠ

생각한 해결책
1. executeQuery의 Fetch Size 조절(현재는 40,000건씩 fetch)
2. mybatis 프레임워크 도입(Spring을 이용한 mybatis 정보는 상당히 많음 ㅠㅠ)

일단 급한 불부터 꺼야 했기에 1번 해결책으로 Fetch 사이즈를 조절해보았다. 10,000건으로 줄여보았는데도 똑같이 Heap space 에러가 발생하였다. 근데 default fetch를 쓰자니 10건씩이고...10배만 늘리자 타협하여 100건씩 fetch하니 일단은 잘 돌아간다.
하지만, 지금까지 대량건 조회는 Spring에서 rowhandler를 써왔기에 java 코드 안에 SQL이 들어가 있어서 관리하기도 불편해서 이번 기회에 java mybatis without Spring 을 도입해보기로 했다.

오류 내용
- AbstractMethodError : Method oracle/jdbc/driver/OracleResultSetImpl.isClosed()Z is abstract
Exception in thread "main" java.lang.AbstractMethodError: Method oracle/jdbc/driver/OracleResultSetImpl.isClosed()Z is abstract
        at oracle.jdbc.driver.OracleResultSetImpl.isClosed(OracleResultSetImpl.java)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:68)
        at cohttp://m.sun.proxy.$Proxy2.isClosed(Unknown Source)
        at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:364)
        at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:337)
        at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:310)
        at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:202)
        at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:66)
        at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:80)
        at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:65)
        at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:336)
        at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:158)
        at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:110)
        at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:90)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:154)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:142)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:75)
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:69)
        at dao.(~~~~~). (~~~~~) ( (~~~~~) .java:9)
        at logic.Main.main(Main.java:74)

구글링 해보니 ojdbc 버전이 안 맞아서 발생하는 오류라는 것 확인. Oracle 홈페이지에 들어가 현재 업무 환경에 맞는 jdbc는 ojdbc6.jar란 것을 확인. ㅡㅡ 시스템은 개판이면서 현재 ojdbc14를 사용 중
출처: https://www.oracle.com/database/technologies/faq-jdbc.html

 

Oracle JDBC Frequently Asked Questions

For byte data, there are three Oracle SQL types: VARCHAR2, LONG and CLOB. VARCHAR2 data is of limited length, is stored directly in a column, and is transmitted to the server in inline packets. LONG data has a much larger limit (2 Gigibytes), is stored via

www.oracle.com

https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc6/11.2.0.4

메이븐 리포지토리에 들어가 ojdbc6.jar 다운로드 후 jar파일 적용하니 mybatis로 쿼리가 동작한다!
(처음부터 rowhandler를 만들면서 테스트 하기엔 무리라고 판단되어 정말 간단한 select 1 from dual 쿼리로 조회)

File list
1. xml 패키지 밑에 mybatis-config.xml (원하는 이름으로 해도 되는지는 추후 확인 필요)
2. sqlMappers 패키지 밑에 "원하는이름"-mapper.xml (SQL 작성 파일)
3. database 패키지 밑에 "원하는이름" .java (getSqlSession() 메소드 존재)
4. dao 패키지 밑에 "원하는이름" .java(mapper id로 쿼리 실행)

to-do : 추후 정보 제거한 핵심만 간추린 소스 업로드

Posted by 知彼知己百戰不殆
,

A조건 : 건수
B조건 : 건수
C조건 : 건수

위와 같이 각 조건별로 건수를 한 방에 출력하고 싶을 때 

select count(case when ~~~~ then 1 end ) as column1
        , count(case when ~~~~ then 1 end ) as column2  
        , count(case when ~~~~ then 1 end ) as column3
  from 테이블명

Posted by 知彼知己百戰不殆
,

0원 초과 1만원 미만 데이터를 구하고 싶은데 >, <를 쓰자니 쿼리가 길어질 거 같고 간단한 건 뭐 없을까 고민하다가 검색

NOT BETWEEN A AND B
=> A 미만 B 초과  

Posted by 知彼知己百戰不殆
,

jar파일 버전을 낮춘 후 다시 DB접속을 시도했으나 이번엔 다음과 같은 오류가 발생했다. ㅠㅠ

원인 : 서버에서 인증서 유효성을 확인할 수 없음

해결 : datasource 마지막 줄에 신뢰 유효성을 확인하기 위한 인증서 검사 무시 여부를 true로 설정
SQLServerDataSource ds = new SQLServerDataSource();
ds.set ~~~
ds.setTrustServerCertificate(true);

https://learn.microsoft.com/ko-kr/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.trustservercertificate?view=sqlclient-dotnet-standard-5.1

 

SqlConnectionStringBuilder.TrustServerCertificate 속성 (Microsoft.Data.SqlClient)

채널이 암호화될 때 신뢰의 유효성을 검사하기 위한 인증서 체인 검사가 무시되는지 여부를 나타내는 값을 가져오거나 설정합니다.

learn.microsoft.com

Exception in thread "main" com.microsoft.sqlserver.jdbc.SQLServerException: "encrypt" 속성이 "true"(으)로 설정되고 "trustServerCertificate" 속성이 "false"(으)로 설정되었지만 드라이버가 SSL(Secure Sockets Layer) 암호화를 사용하여 SQL Server에 대한 보안 연결을 설정할 수 없습니다. 오류: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target. ClientConnectionId:14656c10-20ff-4388-924f-fba7692ec81e
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:4026)
        at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1954)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:3552)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:3172)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:3014)
        at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:1836)
        at com.microsoft.sqlserver.jdbc.SQLServerDataSource.getConnectionInternal(SQLServerDataSource.java:1489)
        at com.microsoft.sqlserver.jdbc.SQLServerDataSource.getConnection(SQLServerDataSource.java:99)
        at database.SQLServerLMSDbConn.getConnection(SQLServerLMSDbConn.java:20)
        at database.DBConnectionFactory.<init>(DBConnectionFactory.java:15)
        at database.Main.main(Main.java:21)
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1497)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:212)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
        at com.microsoft.sqlserver.jdbc.TDSChannel.enableSSL(IOBuffer.java:1843)
        ... 9 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
        at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
        at sun.security.validator.Validator.validate(Validator.java:260)
        at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
        at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
        at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:105)
        at com.microsoft.sqlserver.jdbc.HostNameOverrideX509TrustManager.checkServerTrusted(SQLServerTrustManager.java:88)
        at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:922)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1479)
        ... 17 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:145)
        at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
        at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
        at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
        ... 25 more



Posted by 知彼知己百戰不殆
,