02.Oracle/DataBase2012. 9. 18. 03:26
반응형

출처 : http://ryu1hwan.tistory.com/27

머릿말

오늘은 CASE문에 강의해보도록 하겠습니다.
이전에 DECODE에 대해서 설명드렸는데, DECODE와 동일한 기능을 하는 문장입니다.
DECODE보다 이해하기 쉽고, 사용하기 편한 방법입니다. 단, DECODE보다 코딩양은 약간 길어집니다.
그러므로, 만드는 SQL에서 필요한 상황에 따라 DECODE와 CASE를 섞어 쓰시는게 현명하다고 생각됩니다.


Lesson 7: CASE문

작성방법
SELECT T1.STORE_ID
,T1.STORE_ADDR
,T1.REGION_CD
,T2.REGION_GD
,CASE WHEN T2.REGION_GD = 'S' THEN 'High Grade'
WHEN T2.REGION_GD = 'A' THEN 'High Grade'
ELSE 'Low Grade' END NEW_REGION_GD
FROM SQL_TEST.MA_STORE T1
,SQL_TEST.CD_REGION T2
WHERE T2.REGION_CD = T1.REGION_CD
- STORE의 지역에 대한 등급을 High Grade와 Low Grade로 변경해서 출력한다.
- CASE WHEN을 기술 한 후 조건을 기술하고, THEN 다음에 조건을 만족할 경우의 결과를 적는다.
- CASE WHEN조건을 만족하지 않을 경우 처리한 내용을 ELSE절에 적는다.


중첩된 CASE문
- 여러개의 CASE문을 중첩해서 사용할 수 있다.
SELECT T1.STORE_ID
,T1.STORE_ADDR
,CASE WHEN T1.STORE_SIZE >= 100 THEN
CASE WHEN T2.REGION_GD IN ('S') THEN 'High grade'
WHEN T2.REGION_GD IN ('A','B') THEN 'Mid Grade'
ELSE 'Low Grade'
END
WHEN T1.STORE_SIZE >= 50 THEN
CASE WHEN T2.REGION_GD IN ('S', 'A') THEN 'High Grade'
WHEN T2.REGION_GD IN ('B') THEN 'Mid Grade'
ELSE 'Low Grade'
END
ELSE
CASE WHEN T2.REGION_GD IN ('S', 'A', 'B') THEN 'High Grade'
ELSE 'Low Grade'
END
END STORE_SIZE_GD
FROM SQL_TEST.MA_STORE T1
,SQL_TEST.CD_REGION T2
WHERE T1.REGION_CD = T2.REGION_CD
- STORE의 SIZE에 대한 등급을 STORE의 지역(REGION), STORE_SIZE별로 STORE SIZE등급을 구한다.
- 이러한 중첩된 CASE는 사용자가 원하는 다양한 결과를 얻어 내는데 큰 도움이 된다.

GROUP BY와 CASE/DECODE : GROUP BY컬럼에 CASE/DECODE사용
- GROUP BY를 정의하는 컬럼에 CASE나 DECODE를 사용하는 방법이다.
SELECT CASE WHEN T1.REGION_GD = 'S' THEN 'High Grade'
WHEN T1.REGION_GD = 'A' THEN 'High Grade'
ELSE 'Low Grade' END GRADE
,COUNT(*) REGION_CNT
FROM SQL_TEST.CD_REGION T1
GROUP BY CASE WHEN T1.REGION_GD = 'S' THEN 'High Grade'
WHEN T1.REGION_GD = 'A' THEN 'High Grade'
ELSE 'Low Grade' END;

SELECT
DECODE(T1.REGION_GD,'S','High Grade','A','High Grade','Low Grade') GRADE
,COUNT(*) REGION_CNT
FROM SQL_TEST.CD_REGION T1
GROUP BY DECODE(T1.REGION_GD,'S','High Grade','A','High Grade','Low Grade');
- CASE/DECODE를 통해 REGION_GD가 S나 A인 경우는 High Grade로 표시하고, 나머지는 Low Grade로 집계해서 Region(지역)별로 카운트를 한다.
- 주의 할 점은 GROUP BY에 명시한 내용 그대로 SELECT절에 적어야 한다는 것이다.
- 추가로 예제를 하나 더 보도록 하자.
SELECT CASE WHEN T1.STORE_SIZE >= 100 AND T2.REGION_GD IN ('S') THEN 'High'
WHEN T1.STORE_SIZE >= 100 AND T2.REGION_GD IN ('A','B','C') THEN 'Normal'
WHEN T1.STORE_SIZE < 100 AND T2.REGION_GD IN ('S','A') THEN 'High'
WHEN T1.STORE_SIZE < 100 AND T2.REGION_GD IN ('B','C') THEN 'Low'
END STORE_SIZE_GD
,COUNT(*) STORE_CNT
FROM SQL_TEST.MA_STORE T1
,SQL_TEST.CD_REGION T2
WHERE T1.REGION_CD = T2.REGION_CD
GROUP BY CASE WHEN T1.STORE_SIZE >= 100 AND T2.REGION_GD IN ('S') THEN 'High'
WHEN T1.STORE_SIZE >= 100 AND T2.REGION_GD IN ('A','B','C') THEN 'Normal'
WHEN T1.STORE_SIZE < 100 AND T2.REGION_GD IN ('S','A') THEN 'High'
WHEN T1.STORE_SIZE < 100 AND T2.REGION_GD IN ('B','C') THEN 'Low'
END


GROUP BY + CASE/DECODE : 집계함수 내에 CASE/DECODE사용
- GROUP BY를 사용해서 값을 집계 할 때, CASE/DECODE를 사용해서, 특정 경우에만 값이 집계되도록 하는 방법이다.
SELECT T1.STORE_ID
,SUM(CASE WHEN TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D')='1' THEN 1 END) SUN_ORD
,SUM(CASE WHEN TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D')='2' THEN 1 END) MON_ORD
,SUM(CASE WHEN TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D')='3' THEN 1 END) TUE_ORD
,SUM(CASE WHEN TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D')='4' THEN 1 END) WED_ORD
,SUM(CASE WHEN TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D')='5' THEN 1 END) THU_ORD
,SUM(CASE WHEN TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D')='6' THEN 1 END) FRI_ORD
,SUM(CASE WHEN TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D')='7' THEN 1 END) SAT_ORD
FROM SQL_TEST.HI_ORDER T1
WHERE T1.ORDER_YMD LIKE '200901%'
GROUP BY T1.STORE_ID
ORDER BY T1.STORE_ID;


SELECT
T1.STORE_ID
,SUM(DECODE(TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D'),'1',1,0)) SUN_ORD
,SUM(DECODE(TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D'),'2',1,0)) MON_ORD
,SUM(DECODE(TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D'),'3',1,0)) TUE_ORD
,SUM(DECODE(TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D'),'4',1,0)) WED_ORD
,SUM(DECODE(TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D'),'5',1,0)) THU_ORD
,SUM(DECODE(TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D'),'6',1,0)) FRI_ORD
,SUM(DECODE(TO_CHAR(TO_DATE(T1.ORDER_YMD,'YYYYMMDD'),'D'),'7',1,0)) SAT_ORD
FROM SQL_TEST.HI_ORDER T1
WHERE T1.ORDER_YMD LIKE '200901%'
GROUP BY T1.STORE_ID
ORDER BY T1.STORE_ID;

- 데이터를 STORE_ID별로 GROUP BY한다.
- CASE/DECODE를 사용해서 ORDER_DT의 요일값(1(일요일)~7(토요일))에 따라 주문 건수를 집계
- 예를 들어 ORDER_DT가 요일 값ㅣ 1(일요일)일 때는 숫자 1을 아닌 경우는 0으로 변경해서 합계를 구해 SUN_ORD를 만든다.
- 이와 같은 유형은 데이터 분석 화면을 만들때 많이 사용되는 유형입니다.
- 추가로 하나의 예제를 보도록 하자.
SELECT T1.ORDER_YMD
,SUM(CASE WHEN T2.PROD_SIZE_CD = 'L' THEN 1 END) LARGE_ORD_CNT
,SUM(CASE WHEN T2.PROD_SIZE_CD = 'L' THEN T2.ITEM_SALE_PRC END) LARGE_ORD_AMT
,SUM(CASE WHEN T2.PROD_SIZE_CD = 'M' THEN 1 END) MIDDLE_ORD_CNT
,SUM(CASE WHEN T2.PROD_SIZE_CD = 'M' THEN T2.ITEM_SALE_PRC END) MIDDLE_ORD_AMT
,SUM(CASE WHEN T2.PROD_SIZE_CD = 'S' THEN 1 END) SMALL_ORD_CNT
,SUM(CASE WHEN T2.PROD_SIZE_CD = 'S' THEN T2.ITEM_SALE_PRC END) SMALL_ORD_AMT
FROM SQL_TEST.HI_ORDER T1
,SQL_TEST.HI_ORDER_ITEM T2
WHERE T1.ORDER_YMD LIKE '200901%'
AND T1.ORDER_NO = T2.ORDER_NO
GROUP BY T1.ORDER_YMD
ORDER BY T1.ORDER_YMD
- 주문일자별로 데이터를 GROUP BY한다.
- 주문된 제품의 SIZE별로 주문 건수를 카운트 한다.

GROUP BY + CASE/DECODE : 집계 함수 바깥에 CASE/DECODE를 사용
- GROUP BY와 집계함수를 먼저 사용하고, 집계 함수의 결과에 대해 CASE/DECODE를 사용한다.
SELECT T1.STORE_ID
,SUM(T2.ORDER_AMT) ORDER_AMT
,CASE WHEN SUM(T2.ORDER_AMT) > 15 THEN 'High'
WHEN SUM(T2.ORDER_AMT) > 10 THEN 'Mid'
WHEN SUM(T2.ORDER_AMT) > 0 THEN 'Low'
ELSE 'Bad' END SALE_GD
FROM SQL_TEST.MA_STORE T1
,SQL_TEST.HI_ORDER T2
WHERE T2.STORE_ID = T1.STORE_ID(+)
AND T2.ORDER_YMD(+) = '20090101'
GROUP BY T1.STORE_ID
- STORE별 판매 금액 합계에 따라 판매 등급을 구한다.
- 집계뙨 금액 합계에 따라 15보다 크면 High, 10~15사이이면 Mid, 나머지는 Low로 판매등급을 구한다.
SELECT T3.REGION_GD
,T1.STORE_ID
,SUM(T2.ORDER_AMT) ORDER_AMT
,CASE WHEN T3.REGION_GD = 'S' THEN
CASE WHEN SUM(T2.ORDER_AMT) > 15 THEN 'High'
WHEN SUM(T2.ORDER_AMT) > 10 THEN 'Mid'
ELSE 'Low' END
WHEN T3.REGION_GD = 'A' THEN
CASE WHEN SUM(T2.ORDER_AMT) > 12 THEN 'High'
WHEN SUM(T2.ORDER_AMT) > 9 THEN 'Mid'
ELSE 'Low' END
WHEN T3.REGION_GD = 'B' THEN
CASE WHEN SUM(T2.ORDER_AMT) > 9 THEN 'High'
WHEN SUM(T2.ORDER_AMT) > 5 THEN 'Mid'
ELSE 'Low' END
WHEN T3.REGION_GD = 'C' THEN
CASE WHEN SUM(T2.ORDER_AMT) > 5 THEN 'High'
WHEN SUM(T2.ORDER_AMT) > 3 THEN 'Mid'
ELSE 'Low' END
END SALE_GD
FROM SQL_TEST.MA_STORE T1
,SQL_TEST.HI_ORDER T2
,SQL_TEST.CD_REGION T3
WHERE T2.STORE_ID = T1.STORE_ID(+)
AND T2.ORDER_YMD(+) = '20090101'
AND T3.REGION_CD = T1.REGION_CD
GROUP BY T3.REGION_GD, T1.STORE_ID
- 중첩된 CASE를 이용해서 REGION_GD에 따라 판매등급의 판매금액 기준을 다르게 적용


원래 컬럼을 변경하는 CASE, DECODE문이 자주 나오는 것은 성능상 문제가 있을 수 있다.
- 수작업으로 작성하는 1회성 리포트라면 크게 문제 없다.
- CASE, DECODE를 사용하지 않고 SQL을 작성할 수 있는 가를 고려한다.
- CASE, DECODE를 제거할 수 있도록 테이블을 변경 할 수 있는 가를 고려한다.
- 위의 상황이 불가피 할 경우 상급개발자나 DBAㅘ 함께 성능점검을 하도록 한다.

CASE를 사용할 것인가? DECODE를 사용할 것인가?
- 기본적인 구문은 DECODE가 간단하지만, 복잡한 조건에서는 표현하기가 어렵다.
- DECODE를 이용해 간단히 표현이 가능하면 DECODE를,
- 조건식이 너무 복잡할 경우는 CASE를 사용하도록 하자.


맺음말.
오늘도 저의 지루한 글 읽으시느라고 고생들 하셨습니다.^^
누가 보실지는 모르겠지만, 아무튼, 지금까지 따라 오셨다면,
이젠 SQL문법 자체는 거의 모두 익히신거네요.^^
Posted by 1010
56. Eclipse Etc...2012. 9. 15. 08:07
반응형

-vm
경로

=> jdk경로 지정, -vmargs 이전에 작성해야함

-Dosgi.requiredJavaVersion=1.5 : jdk 버젼이 1.6 일 경우 1.6 으로 적으면 더 빨라짐
-Xms256m : 초기 시작시 메모리 크기(jvm Heap Space)
-Xmx512m : 최대 사용 메모리 크기
-XX:PermSize=64m : 클래스정보 저장 메모리 크기
-XX:MaxPermSize=128m : 클래스정보 저장 최대 메모리 크기(기본값이 8M 라고 함)


* PermGen 영역 설정
jvm 의 메모리 영역 중 PermGen 영역이 존재함
이 영역은 gc에 의해 소거되지 않는 데이터들이 저장되며
순수 class의 정보들(instance가 아닌)이 저장된다.

이 영역이 가득 찰 경우 out of memory 가 발생한다.

(XX는 표준이 아닌 경우라고 한다. 그러므로 작동할지 않을지는 확신할 수 없다고 한다.)


* 속도 향상 ini
-vmargs
-Dosgi.requiredJavaVersion=1.6
-Xvirify:none : 클래스 유효성 검사 생략
-XX:+UseParallelGC : 병렬 gc 사용
-XX:-UseConcMarkSweepGc : 병행 mark-sweep GC 를 수행하여 gui응답을 빠르게 함
-XX:+AggressiveOpts : 컴파일러의 소수점 최적화 기능 작동
-XX:PermSize=128M : Permanent Generation 크기
-XX:NewSize=128M : New Generation 크기
-XX:MaxNewSize=128M : New Generation 최대 크기
-Xms512M : 최소 Heap Memory Size
-Xmm512M : 최대 Heap Memory Size
=> 최대값과 최소값을 같게 해주면 오르락 내리락 하는 경우가 적어 빨리진다고 함


* 추천 Heap Size
1기가 : 256
2~3기가 : 512
4기가 : 1024


* JVM메모리 공간
1. Permanent : class와 method 정보
2. New/Young : 새로 생성되는 instance
3. Old : 만든지 오래된 instance


* 참고 url
http://babolsk.tistory.com/119

[출처] eclipse.ini 설정법|작성자 세직사

 

Posted by 1010
54.iBATIS, MyBatis2012. 9. 15. 08:02
반응형

출처 : http://happy2ni.egloos.com/9609765

[iBatis] 주요 태그 Tag

1] Alias
<typeAlias alias="asName" type="package.SampleClassName"/>

2] 기본 태그
Select : <select id="test" parameterClass="package.ClassName" resultClass="package.ClassName" >
Insert : <insert id="test" parameterClass="package.ClassName" >
Update: <update id="test" parameterClass="package.ClassName" >
Delete : <delete id="test" parameterClass="package.ClassName" >
Statement : <statement id="test" parameterClass="package.ClassName" >

3] 프로퍼티 존재여부
존재할때 : <isPropertyAvailable property="a"></isPropertyAvailable>
존재하지 않을때 : <isNotPropertyAvailable property="a"></isNotPropertyAvailable>

4] 프로퍼티 Null 체크
Null 일때 : <isNull property="a"></isNull>
Null 아닐때 : <isNotNull property="a"></isNotNull>

5] 프로퍼티 Empty 체크
Empty 일때 : <isEmpty property="a"></isEmpty>
Empty 아닐때 : <isNotEmpty property="a"></isNotEmpty>

6] 프로퍼티 값비교
같을때 : <isEqual property="a" compareValue="K"></isEqual>
같지 않을때 : <isNotEqual property="a" compareValue="K"></isNotEqual>

7] ParameterMap
<parameterMap id="paramMap" class="package.ClassName">
<parameter property="id" />
<parameter property="name" javaType="java.lang.String" jdbcType="VARCHAR" mode="IN"/>
<parameter property="msg" javaType="java.lang.String" jdbcType="VARCHAR" mode="OUT"/>
</parameterMap>

8] ResultMap
<resultMap id="reMap" class="package.ClassName">
<result property="id" column="test_id" />
</resultMap>

9] Dynamic
<select>
select a from test
<dynamic prepend="where">
<isNotNull property="a" >id = #a#</isNotNull>
<isNotNull property="b" prepend="AND">name = #b#</isNotNull>

<isNotNull property="c" prepend="AND" open="(" close=")">
<isNotNull property="c" > no = #c#</isNotNull>
</isNotNull property="c" prepend="OR">no_as = #d#</isNotNull>
</isNotNull>
</dynamic>
</select>

 

Posted by 1010
01.JAVA/Java2012. 9. 15. 08:01
반응형

StackTraceElement STE = Thread.currentThread().getStackTrace()[1];

String className = STE.getClassName();
String methodName = STE.getMethodName());

 

Posted by 1010
01.JAVA/Java2012. 9. 15. 07:58
반응형
public class Test{
public static void main(String[] args){
String[] command = {"/bin/sh","-c","실행시킬 쉘 스크립트"};
int i;
try{
Process ps = Runtime.getRuntime().exec(command);
ps.waitFor();
System.out.println(ps.exitValue());
ps.destroy();
}catch(Exception e){
e.printStackTrace();
}
}
}

 

Posted by 1010
55.jrebel2012. 9. 13. 03:35
반응형

JRebel Social: Getting Started with a Step-by-step Tutorial

JRebel Social is free to use for non-commercial development, and the only thing you need to do to use it, is let your network know it exists, once per month. Simply login and register using your Twitter or Facebook account and then pickup your online or offline license keys.

As icing on the cake, you can see how much time you’ve saved by eradicating redeploys (and builds) from your Java development process, on your personal dashboard.

***

In order to take advantage of the power of JRebel through JRebel Social, all of you have to do is to take the following simple steps.

Step 1: Download and install JRebel 4.5

1. Go to http://www.zeroturnaround.com/jrebel/current/ using your browser.

2. Download and unzip JRebel JAR Installer (or Windows Installer for Windows platform)

3. Start JRebel JAR Installer.

Under JRebel installation directory, type “java -jar jrebel-setup.jar


Step 2: Register for JRebel Social

1. In the Activate JRebel pane of the JRebel Configuration Wizard, select I want to use JRebel Social(FREE for non-commercial use).

2. Log in using your Facebook or Twitter account.

3. Register.


Step 3: Activate your license

Copy and paste the license code in the registration page into the license code box in the Configuration Wizard.

Congratulations! Your JRebel license is now activated and you are ready to go.

Step 4: Acquire offline token for offline usage (Optional step)

In order to use JRebel Social, you have to be in the “connected state” to the JRebel Social server through the net. Now if you want to use JRebel offline for a day, you can do create offline token following the steps below.

1.From your dashboard, click “Go Off-line for 24 h“.

2. Observe the message indicating the JRebel off-line token has been extended.

3. Either restart your container or go to your JRebel installation directory and run bin\go-offline (for Windows) or bin/go-offline.sh (For Mac/Linux).

Now you are ready to use JRebel offline for a day.

Posted by 1010
54.iBATIS, MyBatis2012. 9. 13. 03:31
반응형

출처 : http://lonelycat.tistory.com/289 

 

<statement id="CHECK_SUB_CONTENT_TYPE_FOR_DELETE" resultClass="java.lang.String">
SELECT
COUNT(*) TOTAL_COUNT
FROM
SUB_CONTENT_TYPE
<iterate prepend="WHERE" property="deleteContentTypeList" open="(" conjunction="," close=")">
CONTENT_TYPE IN #deleteContentTypeList[]#
</iterate>
</statement>

<statement id="CHECK_SUB_CONTENT_TYPE_FOR_DELETE" resultClass="java.lang.String">
SELECT
COUNT(*) TOTAL_COUNT
FROM
SUB_CONTENT_TYPE
<iterate prepend="WHERE CONTENT_TYPE IN " property="deleteContentTypeList" open="(" conjunction="," close=")">
#deleteContentTypeList[]#
</iterate>
</statement>


<statement id="CHECK_SUB_CONTENT_TYPE_FOR_DELETE" parameterClass="java.util.List" resultClass="java.lang.String">
SELECT
COUNT(*) TOTAL_COUNT
FROM
SUB_CONTENT_TYPE
<dynamic prepend="WHERE">
<iterate property="deleteContentTypeList" open="(" conjunction="," close=")">
CONTENT_TYPE IN #deleteContentTypeList[]#
</iterate>
</dynamic>
</statement>


버근지 뭔지 몰라도 위의 방식은 하나도 안된다. property속성을 쓰면 안되는건지...
근데 되는 사람들도 있는 것 같고..

<statement id="CHECK_SUB_CONTENT_TYPE_FOR_DELETE" resultClass="java.lang.String">
SELECT
COUNT(*) TOTAL_COUNT
FROM
SUB_CONTENT_TYPE
<dynamic prepend="WHERE">
<iterate open="CONTENT_TYPE IN (" close=")" conjunction="," >
#[]#
</iterate>
</dynamic>
</statement>


이것처럼 아예 property 속성을 없애고, list의 이름을 없이 하면 잘됨.

참고:http://lostsin.tistory.com/tag/iBATIS

sql의 xml설정은 다음과 같이 하고

<delete id="deletes" >
DELETE FROM users
<dynamic prepend="WHERE id IN">
<iterate open="(" conjunction="," close=")">
#[]#
</iterate>
</dynamic>
</delete>


DAO는 다음과 같이 한다
public int delete(Integer[] ids) {
return getSqlMapClientTemplate().delete("users.deletes", ids);
}

해당 쿼리는 <iterate> 구문에 의하여 WHERE id IN (1,2,3,4,5) 방식으로
값이 매핑되게 된다.


보너스1.
List<>를 사용하는 방법도 xml 쿼리 부분은 동일하다.

List<String> list = new ArrayList<String>(3);

list.add("1");

list.add("2");

list.add("3");

List objs = sqlMapClient.queryForList("select-test",list);




보너스2.
parameterClass="map" 을 사용할 땐

     WHERE

session_id IN

<iterate property="sessionIds" open="(" close=")" conjunction=",">

#key[]#

</iterate>

hash의 key 값으로 사용된 string을 지정해주면 된다 (?)


추가.

HashMap map = new HashMap();
map.put("deleteContentTypeList", deleteContentTypeList);
map.put("updateId", updateId);
map.put("updateTime", updateTime);

this.update("contenttype.DELETE_CONTENT_TYPE", map);


<statement id="DELETE_CONTENT_TYPE">
UPDATE
CONTENT_TYPE
SET
STATUS = 'D'
, UPDATE_ID = #updateId#
, UPDATE_TIME = #updateTime#
<dynamic prepend="WHERE">
<iterate property="deleteContentTypeList" open="CONTENT_TYPE IN (" close=")" conjunction=",">
#deleteContentTypeList[]#
</iterate>
</dynamic>
</statement>


이건 또 된다. map에 넣어서 넘겨주면 멀쩡히 잘 되는군...

# 추가
list 를 패러미터로 전달 시 iterate 태그에서 property 를 설정하면(map으로 넘겼을 떄 말고),
전달된 list 에서 해당 property 를 찾으려고 시도하는 것 같다.
<iterate> 태그에서 property 속성을 제거하면 정상적으로 작동한다.

<select id="selectSomething" parameterClass="list">
// select something and use iterate
<iterate> // iterate 태그 내 property 속성을 제거하라
#someList[]#
</iterate>
</select>

Posted by 1010
반응형

이클립스 속도 향상 (eclipse.ini 수정)


최근 이클립스가 버벅대서 오랜만에 이클립스 속도 향상 정보를 정리해본다.


eclipse.ini 수정


1) Before


-startup

plugins/org.eclipse.equinox.launcher_1.1.0.v20100507.jar

--launcher.library

plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.1.R36x_v20100810

-product

org.eclipse.epp.package.jee.product

--launcher.defaultAction

openFile

--launcher.XXMaxPermSize

256M

-showsplash

org.eclipse.platform

--launcher.XXMaxPermSize

256m

--launcher.defaultAction

openFile

-vmargs

-Dosgi.requiredJavaVersion=1.5

-Xms40m

-Xmx512m



2) After


-vmargs

-Dosgi.requiredJavaVersion=1.6

-Xverify:none

-XX:+UseParallelGC

-XX:-UseConcMarkSweepGC

-XX:+AggressiveOpts

-XX:PermSize=128M

-XX:MaxPermSize=128M

-XX:MaxNewSize=128M

-XX:NewSize=128M

-Xms512m

-Xmx512m


3) 설명

-Dosgi.requiredJavaVersion=1.6 => JDK 1.6 이상을 설치했을 경우에 1.6으로 설정하면 속도가 빨라진다.

-Xverify:none => 클래스의 유효성을 검사 생략. (시작 시간이 줄어 빨라진다.)
-XX:+UseParallelGC => 병렬 가비지 컬렉션 사용. (병렬 처리로 속도 향상)
-XX:+AggressiveOpts => 컴파일러의 소수점 최적화 기능을 작동시켜 빨라진다.
-XX:-UseConcMarkSweepGC => 병행 mark-sweep GC 수행하여 이클립스 GUI의 응답을 빠르게한다.

-XX:PermSize=128M => Permanent Generation(영구 영역) 크기(Out Of Memory 에러시 크기 조절)

-XX:MaxPermSize=128M => 최대 Permanent Generation 크기

-XX:NewSize=128M => New Generation(새 영역) 크기

-XX:MaxNewSize=128M => New Generation(새 영역) 의 최대 크기


-Xms512m : 이클립스가 사용하는 최소 Heap 메모리
-Xmx512m : 이클립스가 사용하는 최대 Heap 메모리
최소와 최대를 같은 값으로 설정하면 오르락 내리락 하지않아 빨라진다.

혹시, 오류로 이클립스가 죽는다면 설정값을 한줄씩 지우거나 숫자를 변경해서 테스트 후 사용하기바람.

[메모리 정의 예]
1 기가 이하 메모리인 컴퓨터인 경우 => -Xms256m -Xmx256m
2 기가 ~ 3 기가 메모리인 컴퓨터 => -Xms512m -Xmx512m
4기가 이상 메모리인 컴퓨터 => -Xms1024m -Xmx1024m

[ 참고 ]
JVM 은 3가지 메모리 영역을 관리합니다.
1. Permanent(영구) 영역 : JVM 클래스와 메소드를 위한 공간. = PermSize 설정
2. New/Young 영역 : 새로 생성된 개체들을 위한 공간. = NewSize 설정
3. Old 영역 : 만들어진지 오래된 객체들의 공간.(New 영역에서 이동해 온다)



<원본글 : http://blog.naver.com/sungback/90097516641 >
Posted by 1010
02.Oracle/DataBase2012. 9. 2. 08:01
반응형

출처 : http://scidb.tistory.com/entry/SQL-Tuning-Advisor

SQL Tuning Advisor

개념 :
- Oracle 10g 의 새기능인 Automatic Workload Repository(AWR) 의 튜닝 솔루션인
Server-Based Advisors의 콤포넌트 중의 하나이다.
- Server-Based Advisors 는 다음과 같이구성된다.
Automatic Database Diagnostic Monitor (ADDM)
SQL Tuning Advisor
SQL Access Advisor
Shared Pool Advisor
MTTR Advisor
- SQL Tuning Advisor 는 SQL 구문들을 분석하여 튜닝방법을 제안한다.
- 튜닝방법을 제안하는 것에서 그치지 않고 쉽게적용할수 있도록 도와주기도 한다.


사용방법:
-엔터프라이져 매니져를 통해 관리할수도 있지만 여기서는 DBMS_SQLTUNE 패키지를
사용하기로 한다.

1) 튜닝 Task 생성

Declare
ret_val varchar2(2000);
Begin
ret_val:=dbms_sqltune.create_tuning_task(sql_text=>
'SELECT *FROM EMP WHERE EMPNO=7934');

dbms_output.put_line('Output: 'ret_val);

end;/

OUTPUT: TASK_00004

2) 튜닝가이드 생성

Exec Dbms_sqltune.execute_tuning_task('TASK_00004');


3) 튜닝 리포트 생성
set serveroutput on size 999999
set long 999999
select dbms_sqltune.report_tuning_task ('TASK_00004') from dual;

4)결과분석

GENERAL INFORMATION SECTION
----------------------------------------------------
Tuning Task Name : TASK_00004
Scope : COMPREHENSIVE
Time Limit(seconds): 1800
Completion Status : COMPLETED
Started at : 11/06/2003 01:47:38

사용자 삽입 이미지

-------------------------------------------------------------------------------------------

위 결과를 보면 recommendation 항목에서 튜닝제안을 했으며 구체적인 스크립트까지
제시하고 있다.
Rationale 항목에서는 튜닝방법대로 했을경우 옵티마이져가 어떻게 반응하는지를 보여준다.
위의 예제에서는 통계정보를 생성하면 실행계획이 바뀐다는점을 알려주고 있다.
신기하지 않은가?

 

Posted by 1010
02.Oracle/DataBase2012. 9. 2. 07:59
반응형

출처: http://scidb.tistory.com/entry/다양한-검색조건의-튜닝방법

 

다양한 검색조건의 튜닝방법

업무적으로 볼때 조회화면의 검색조건들의 조합은 참으로 다양하다.
아래의 SQL 을 보면 WHERE 절의 모든 변수(:v_grade , :v_loc , :v_hiredate )에 값이 생략이 가능하다.
즉 모든 변수에 값이 들어올수도 있고 일부만 들어올수도 있고 전체가 안들어 올수도 있다.
where 절의 대부분이 그런조건이라고 가정하면 그런 SQL 들은 튜닝하기가 참 난감하다.
이럴때 당신이라면 어떻게 할것인가?
전통적인 튜닝 방법인 UNION ALL 로 모두 쪼개서 분리 할것인가?
아래의 인덱스 구조와 SQL 을 보자.

EMP 인덱스:
1) PK_EMP ( EMPNO )
2) EMP_IDX1 ( SAL )
3) EMP_IDX2 ( HIREDATE )
4) EMP_IDX3 ( DEPTNO )

DEPT 인덱스 :
1) PK_DEPT ( DEPTNO )
2) DEPT_IDX1 ( LOC )

SALGRADE 인덱스:
1) PK_SALGRADE( GRADE )
2) SALGRADE( HISAL, LOSAL)

1. 다양한 조건검색을 OR 로 처리할경우(원본 SQL)

SELECT a.empno, a.ename, a.job, b.dname, a.sal
FROM EMP a,
DEPT b,
SALGRADE c
WHERE a.deptno = b.deptno
and a.sal between c.losal and c.hisal
and (c.grade = :v_grade or :v_grade is null) --> 변수에 NULL 대입
and (b.loc = :v_loc or :v_loc is null) --> 변수에 NULL 대입
and (a.hiredate = :v_hiredate or :v_hiredate is null); --> 변수 :v_hiredate 에 '1980-12-17' 값을 대입한다.


 

물론 위의 SQL 을 아래처럼 나타태도 PLAN 상으로는 같다.

SELECT a.empno, a.ename, a.job, b.dname, a.sal
FROM EMP a,
DEPT b,
SALGRADE c
WHERE a.deptno = b.deptno
and a.sal between c.losal and c.hisal
and c.grade LIKE :v_grade||'%' --> 변수에 NULL 대입
and b.loc LIKE :v_loc||'%' --> 변수에 NULL 대입
and a.hiredate LIKE :v_hiredate||'%'; --> 변수 :v_hiredate 에 '1980-12-17' 값을 대입한다.



-------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------
| 1 | NESTED LOOPS | | 1 | 1 |00:00:00.01 | 21 |
| 2 | NESTED LOOPS | | 1 | 1 |00:00:00.01 | 19 |
|* 3 | TABLE ACCESS FULL | SALGRADE | 1 | 5 |00:00:00.01 | 8 |
|* 4 | TABLE ACCESS BY INDEX ROWID| EMP | 5 | 1 |00:00:00.01 | 11 |
|* 5 | INDEX RANGE SCAN | EMP_IDX1 | 5 | 14 |00:00:00.01 | 3 |
|* 6 | TABLE ACCESS BY INDEX ROWID | DEPT | 1 | 1 |00:00:00.01 | 2 |
|* 7 | INDEX UNIQUE SCAN | PK_DEPT | 1 | 1 |00:00:00.01 | 1 |
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

3 - filter((:V_GRADE IS NULL OR "C"."GRADE"=TO_NUMBER(:V_GRADE)))
4 - filter((:V_HIREDATE IS NULL OR "A"."HIREDATE"=TO_DATE(:V_HIREDATE,'YYYY-MM-DD')))
5 - access("A"."SAL">="C"."LOSAL" AND "A"."SAL"<="C"."HISAL")
6 - filter(("B"."LOC"=:V_LOC OR :V_LOC IS NULL))
7 - access("A"."DEPTNO"="B"."DEPTNO")


해석 : 위 PLAN 을 보면 :v_hiredate 에 값이 들어 왔으므로 당연히 EMP_IDX2 인덱스를 먼저
ACCESS 해야 하지만 엉뚱한 테이블 부터 ACCESS 하여서 비효율이 발생 하였다.
즉 동적으로 변수값이 들어옴에 따라 PLAN 을 최적화 하지 못한다는 의미이다.
물론 버젼이 11g 라면 동적으로 최적화 할수 있는 기능(Adaptive Cursor sharing)이 있지만
항상 그렇게 되는건 아니다.
그러면 이런 문제를 해결하기위해 어떻게 해야 할까?
아래의 2~4 번에 해답이 있다.

2.엑세스 형태별로 UNION ALL 로 분리함

먼저 UNION ALL 로 분리하는 기준은 똑똑한 조건에 먼저 우선순위를 주었다.
다시말하면 :v_hiredate 는 굉장히 똑똑한 조건이므로 값이 들어오면 :v_grade 나 :v_loc 에 값이
들어오던 들어오지 않던 대세에 지장이 없다는 의미이다.
마찬가지 방법으로 :v_hiredate 가 들어오지 않는 상황에서는 두번째로 똑똑한 조건인 :v_grade 에
값이 들어오면 :v_loc 이 들어오던 들어오지 않던 중요하지 않다는 의미이다.
따라서 순서는 :v_hiredate --> :v_grade --> :v_loc 로 하였다.
실행시에 다른변수에는 값을 넣지않고 :v_hiredate 만 '1980-12-17' 값을 대입한다.


SELECT .... --> :v_hiredate 가 들어 왔을때
WHERE a.deptno = b.deptno
and a.sal between c.losal and c.hisal
and (c.grade = :v_grade or :v_grade is null)
and (b.loc = :v_loc or :v_loc is null)
and a.hiredate = :v_hiredate and :v_hiredate is not null
UNION ALL
SELECT .... --> :v_hiredate 가 안들어 오고 :v_grade 가 들어올때
WHERE a.deptno = b.deptno
and a.sal between c.losal and c.hisal
and c.grade = :v_grade
and (b.loc = :v_loc or :v_loc is null)
and :v_hiredate is null and :v_grade is not null
UNION ALL
SELECT .... --> :v_hiredate 가 안들어 오고 :v_grade 가 안들어오고 :v_loc 가 들어올때
WHERE a.deptno = b.deptno
and a.sal between c.losal and c.hisal때
and c.grade = :v_grade
and b.loc =:v_loc
and :v_hiredate is null and :v_grade is null and :v_loc is not null
UNION ALL
SELECT .... --> 변수에 아무것도 안들어 왔을때
WHERE a.deptno = b.deptno
and a.sal between c.losal and c.hisal
and :v_hiredate is null
and :v_grade is null
and :v_loc is null ;


---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------
| 1 | UNION-ALL | | 1 | 1 |00:00:00.05 | 8 |
|* 2 | FILTER | | 1 | 1 |00:00:00.05 | 8 |
|* 3 | TABLE ACCESS BY INDEX ROWID | SALGRADE | 1 | 1 |00:00:00.05 | 8 |
| 4 | NESTED LOOPS | | 1 | 3 |00:00:00.08 | 7 |
| 5 | NESTED LOOPS | | 1 | 1 |00:00:00.04 | 5 |
| 6 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 1 |00:00:00.02 | 3 |
|* 7 | INDEX RANGE SCAN | EMP_IDX2 | 1 | 1 |00:00:00.01 | 2 |
|* 8 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 1 |00:00:00.02 | 2 |
|* 9 | INDEX UNIQUE SCAN | PK_DEPT | 1 | 1 |00:00:00.01 | 1 |
|* 10 | INDEX RANGE SCAN | SALGRADE_IDX1 | 1 | 1 |00:00:00.01 | 2 |
|* 11 | FILTER | | 1 | 0 |00:00:00.01 | 0 |
| 12 | NESTED LOOPS | | 0 | 0 |00:00:00.01 | 0 |
| 13 | NESTED LOOPS | | 0 | 0 |00:00:00.01 | 0 |
| 14 | TABLE ACCESS BY INDEX ROWID | SALGRADE | 0 | 0 |00:00:00.01 | 0 |
|* 15 | INDEX RANGE SCAN | PK_SALGRADE | 0 | 0 |00:00:00.01 | 0 |
| 16 | TABLE ACCESS BY INDEX ROWID | EMP | 0 | 0 |00:00:00.01 | 0 |
|* 17 | INDEX RANGE SCAN | EMP_IDX1 | 0 | 0 |00:00:00.01 | 0 |
|* 18 | TABLE ACCESS BY INDEX ROWID | DEPT | 0 | 0 |00:00:00.01 | 0 |
|* 19 | INDEX UNIQUE SCAN | PK_DEPT | 0 | 0 |00:00:00.01 | 0 |
|* 20 | FILTER | | 1 | 0 |00:00:00.01 | 0 |
|* 21 | TABLE ACCESS BY INDEX ROWID | SALGRADE | 0 | 0 |00:00:00.01 | 0 |
| 22 | NESTED LOOPS | | 0 | 0 |00:00:00.01 | 0 |
| 23 | NESTED LOOPS | | 0 | 0 |00:00:00.01 | 0 |
| 24 | TABLE ACCESS BY INDEX ROWID| DEPT | 0 | 0 |00:00:00.01 | 0 |
|* 25 | INDEX RANGE SCAN | DEPT_IDX1 | 0 | 0 |00:00:00.01 | 0 |
| 26 | TABLE ACCESS BY INDEX ROWID| EMP | 0 | 0 |00:00:00.01 | 0 |
|* 27 | INDEX RANGE SCAN | EMP_IDX3 | 0 | 0 |00:00:00.01 | 0 |
|* 28 | INDEX RANGE SCAN | PK_SALGRADE | 0 | 0 |00:00:00.01 | 0 |
|* 29 | FILTER | | 1 | 0 |00:00:00.01 | 0 |
| 30 | MERGE JOIN | | 0 | 0 |00:00:00.01 | 0 |
| 31 | SORT JOIN | | 0 | 0 |00:00:00.01 | 0 |
|* 32 | HASH JOIN | | 0 | 0 |00:00:00.01 | 0 |
| 33 | TABLE ACCESS FULL | DEPT | 0 | 0 |00:00:00.01 | 0 |
| 34 | TABLE ACCESS FULL | EMP | 0 | 0 |00:00:00.01 | 0 |
|* 35 | FILTER | | 0 | 0 |00:00:00.01 | 0 |
|* 36 | SORT JOIN | | 0 | 0 |00:00:00.01 | 0 |
| 37 | INDEX FULL SCAN | SALGRADE_IDX1 | 0 | 0 |00:00:00.01 | 0 |
---------------------------------------------------------------------------------------------------

Predicate Information (지면관계상 생략)

해석 : PLAN 이 개발자가 의도한대로 분리되었고 A-Rows 와 Buffers 를 보면 분리된 SQL 중에서 첫번째
SQL 만 값이 있다.
하지만 최적의 SQL 이 되려면 아직도 멀었다.

3.UNION ALL 로 분리된 각각의 SQL 최적화

:v_grade 에 값이 들어오지 않는다면 더이상 SALGRADE 테이블은 필요가 없다.
과감히 FROM 절에서 삭제하자.
물론 a.sal 컬럼의 값에 NULL 이 있다면 답이 달라지므로 주의해야 한다.

SELECT ....
FROM EMP a,
DEPT b,
SALGRADE c
WHERE a.deptno = b.deptno
and a.sal between c.losal and c.hisal
and (c.grade = :v_grade or :v_grade is null)
and (b.loc = :v_loc or :v_loc is null)
and a.hiredate = :v_hiredate
and :v_hiredate is not null
UNION ALL
SELECT ....
FROM EMP a,
DEPT b,
SALGRADE c
WHERE a.deptno = b.deptno
and a.sal between c.losal and c.hisal
and c.grade = :v_grade
and (b.loc = :v_loc or :v_loc is null)
and :v_hiredate is null
and :v_grade is not null
UNION ALL
SELECT ....
FROM EMP a,
DEPT b -->
SALGRADE 테이블은 필요가 없음
WHERE a.deptno = b.deptno
and b.loc =:v_loc
and :v_hiredate is null
and :v_grade is null
and :v_loc is not null
UNION ALL
SELECT ....
FROM EMP a,
DEPT b -->
SALGRADE 테이블은 필요가 없음
WHERE a.deptno = b.deptno
and :v_hiredate is null
and :v_grade is null
and :v_loc is null ;


PLAN 정보 및 Predicate Information (지면관계상 생략)


4.NVL 혹은 DECODE 함수의 활용

UNION ALL 로 분리하면 옵티마이져 입장에서는 환영할 일이지만 개발자 입장에서 보면 반복적인 코딩이 증가하고 유지보수시 일량이 늘어나는 단점이 있다.
그렇다면 코딩량을 줄일수 있는 최적의 방법은 없는것일까?

물론 방법이 있다.
아래의 SQL 을 보자.
아래의 SQL 은 UNION ALL로 분리된 SQL 중에서 마지막 2개의 SQL 을 합친 것이다.

SELECT a.empno, a.ename, a.job, b.dname, a.sal
FROM EMP a,
DEPT b
WHERE a.deptno = b.deptno
and b.loc = decode(:v_loc, null, b.loc, :v_loc) --:V_LOC 에 'CHICAGO' 대입
and :v_hiredate is null
and :v_grade is null
and :v_loc is not null


----------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------
| 1 | CONCATENATION | | 1 | 6 |00:00:00.03 | 7 |
|* 2 | FILTER | | 1 | 0 |00:00:00.01 | 0 |
| 3 | TABLE ACCESS BY INDEX ROWID | EMP | 0 | 0 |00:00:00.01 | 0 |
| 4 | NESTED LOOPS | | 0 | 0 |00:00:00.01 | 0 |
| 5 | TABLE ACCESS BY INDEX ROWID| DEPT | 0 | 0 |00:00:00.01 | 0 |
|* 6 | INDEX FULL SCAN | DEPT_IDX1 | 0 | 0 |00:00:00.01 | 0 |
|* 7 | INDEX RANGE SCAN | EMP_IDX3 | 0 | 0 |00:00:00.01 | 0 |
|* 8 | FILTER | | 1 | 6 |00:00:00.03 | 7 |
| 9 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 6 |00:00:00.03 | 7 |
| 10 | NESTED LOOPS | | 1 | 8 |00:00:00.15 | 5 |
| 11 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 1 |00:00:00.01 | 3 |
|* 12 | INDEX RANGE SCAN | DEPT_IDX1 | 1 | 1 |00:00:00.01 | 2 |
|* 13 | INDEX RANGE SCAN | EMP_IDX3 | 1 | 6 |00:00:00.01 | 2 |
----------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter((:V_LOC IS NOT NULL AND :V_GRADE IS NULL AND :V_HIREDATE IS NULL AND :V_LOC IS NULL))
6 - filter("B"."LOC" IS NOT NULL)
7 - access("A"."DEPTNO"="B"."DEPTNO")
8 - filter((:V_LOC IS NOT NULL AND :V_GRADE IS NULL AND :V_HIREDATE IS NULL AND :V_LOC IS NOT NULL))
12 - access("B"."LOC"=:V_LOC)
13 - access("A"."DEPTNO"="B"."DEPTNO")


해석 : DECODE 함수를 사용함으로써 맨마지막 2개의 SQL 을 합쳤으나 옵티마이져가 조건이 들어오는 경우와
들어오지 않는경우를 옵티마이져는 자동으로 UNION ALL 로 분리하였다.
그러나 항상 이렇게 분리되는것은 아니므로 주의를 요한다.

5.SQL 의 최종모습

SELECT a.empno, a.ename, a.job, b.dname, a.sal
FROM EMP a,
DEPT b,
SALGRADE c
WHERE a.deptno = b.deptno
and a.sal between c.losal and c.hisal
and (c.grade = :v_grade or :v_grade is null)
and (b.loc = :v_loc or :v_loc is null)
and a.hiredate = :v_hiredate
and :v_hiredate is not null
UNION ALL
SELECT a.empno, a.ename, a.job, b.dname, a.sal
FROM EMP a,
DEPT b,
SALGRADE c
WHERE a.deptno = b.deptno
and a.sal between c.losal and c.hisal
and c.grade = :v_grade
and (b.loc = :v_loc or :v_loc is null)
and :v_hiredate is null
and :v_grade is not null

UNION ALL
SELECT a.empno, a.ename, a.job, b.dname, a.sal
FROM EMP a,
DEPT b
WHERE a.deptno = b.deptno
and b.loc = nvl(:v_loc, b.loc)
and :v_hiredate is null
and :v_grade is null ;


결론 : 검색화면의 경우 다양한 검색조건들이 들어올수 있다.
기본적인 전략은 아래와 같이 순서대로 3가지 이다.
1.똑똑한 조건을 기준으로 UNION ALL 로 분리한다.(2번에 해당)
2.UNION ALL 로 분리된 각각의 SQL 을 최적화 한다.(3번에 해당) --> FROM 절의 테이블 갯수가 달라진다.
3.DECODE 나 NVL 을 사용함으로서 과도한 UNION ALL 로 분리되어 거대해지고
Shared Pool 에 무리를 줄수도 있는 SQL 을 통합하여 하나로 만든다.(4번에 해당)

Posted by 1010