database.sarang.net
UserID
Passwd
Database
DBMS
MySQL
PostgreSQL
Firebird
ㆍOracle
Informix
Sybase
MS-SQL
DB2
Cache
CUBRID
LDAP
ALTIBASE
Tibero
DB 문서들
스터디
Community
공지사항
자유게시판
구인|구직
DSN 갤러리
도움주신분들
Admin
운영게시판
최근게시물
Oracle Q&A 21050 게시물 읽기
No. 21050
쿼리좀 도와 주세요. 감사합니다.
작성자
unimeek
작성일
2004-12-14 14:59
조회수
3,831

TABLE TEST1
NUM
1
2
3
4
5

TABLE TEST2
NUM
1

이렇게 있을때

select count(*) as count from test1 t1, test2 t2 where t1.num != t2.num

하면 TEST1.NUM 이 1이 아닌 2,3,4,5 가 카운트 되서 select 되쟌아요.

의도는 위에서 처럼 TEST2 테이블에 있는 NUM은 제외하고 TEST1을 카운트 하고 싶은것 입니다.

근데 TEST2 테이블이 비어 있을경우 즉 TEST2.NUM에 VALUE가 아무것도 없을 경우

쿼리를 돌리면

TEST1.NUM 1,2,3,4,5가 SELECT가 되지 않고 카운트가 "0" 이 되는데 제가 의도한 바 대로 쿼리가 될려면 어떻게 해야 하죠.?

이 글에 대한 댓글이 총 11건 있습니다.

SELECT *
FROM TABLE1 T1, TABLE2 T2
WHERE T1.NUM != NVL(T2.NUM, 0)

 

이거 얘기하시는거에요??

 

초보리플러님이 2004-12-14 15:16에 작성한 댓글입니다. Edit

아닙니다.

제가 질문을 잘못 했습니다.

TEST2에 있는 내용을 제외해서 TEST1에서 쿼리를 하고 싶었던 것입니다.

 

select t1.num from test1 t1

where t1.num not in

(select t1.num from test1 t1, test2 t2 where t1.num = t2.num)

 

이런 식으로 해결 했습니다.

 

아주 초보적인 쿼리였는데 ^^; 생각을 잘못 하고 있어서..

 

근데 이렇게 쿼리 하는게 맞져.?

 

unimeek님이 2004-12-14 15:54에 작성한 댓글입니다. Edit

select t1.num from test1 t1

where t1.num not in

(select t1.num from test2 t2 where t1.num = t2.num)

 

이렇게 하시는게 더 바람직합니다.

t1을 한번 읽었기 때문에 서브쿼리에서 또 읽을 필요 없죠...

 

select count(*)
from test1 a
where not exists (select 'x' from test2 b where a.num = b.num) 

 

테스트는 안해봤지만, not exists를 사용하는 것이 속도면에서는 더 낫지 않을까 생각됩니다. 

 

p.s 고수님들께 질문... not exists도 ( )안의 조건에 하나라도 만족하면 더이상 수행하지 않는 거죠? 혹시나 잘못된 지식이 전달될까 하여.... 전 더 책을 찾아봐야 겠습니다.

 

 

민윤기(amgblue)님이 2004-12-14 16:14에 작성한 댓글입니다.

select t1.num from test1 t1

where t1.num not in

(select t1.num from test1 t1, test2 t2 where t1.num = t2.num)

 

SELECT NUM FROM TEST1

MINUS

SELECT NUM FROM TEST2

 

ㅡ.ㅡ NOT IN 즐.~

ㅡ.ㅡ님이 2004-12-14 16:15에 작성한 댓글입니다.
이 댓글은 2004-12-14 16:16에 마지막으로 수정되었습니다. Edit

in 문일경우 인덱스를 탄다면 해당 조건의 값을 발견해도 그 해당 조건의 값이 한개가 아닐수 있기 때문에 더이상 발견되지 않을때까지 조회를 합니다.

 

exists 문의 경우는 무조건 발견되는 그시점에서 true 로 조건충족해서 빠져나오구요. 예를 들어 코드로 100만건이 들어가 있고 '01'코드가 90만건이고 '02'코드가 10만건이면 01을 in으로 조회시 90만건을 가져오지만 exists로 조회하면 첫Row(index가 잡혀있다고 가정시) 에서 바로 조건충족하므로 검색을 중단하죠.

 

두 성능의 차이는 확연히 아실수 있을겁니다.

눈팅님이 2004-12-14 16:35에 작성한 댓글입니다. Edit

위에 약간 잘못된게 있내요.

----------unimeek님  sql1

select t1.num from test1 t1

where t1.num not in

(select t1.num from test2 t2 where t1.num = t2.num)

----------unimeek님  sql1

select count(*)
from test1 a
where not exists (select 'x' from test2 b where a.num = b.num) 

자세이 where 조건을 보시면 둘다 sub query이면서 t1 조건이 sub query안에 존재합니다. 그럼 서브query는 몇번 실행될까요?

t1의 레코드수만큼 실행됩니다.

sql1 번은 다음과 같이 수정가능합니다.

---- sql3

select t1.num from test1 t1

where t1.num not in

(select t2.num from test2 t2 )

 

이건 상황이 많이 달라집니다. 똑같은 sub query로 보이지만 이건 sub qyery가 딱 한번 실행됩니다. 파서는 위의 sql문을 파싱하면서 join 형태로 바꿉니다. 그래서 sql이 두번만 실행됩니다.(간혹 사람들은 sql의 본연의 뜻을 잊습니다. sql은 집합형 언어입니다. 생각을 바꿔서 집합이란것을 가끔식 떠올린다면, 엄청난 속도의 향상을 경험하실수 있을것입니다.)

보통 exists 보다 in 이 빠르다는 이유가 여기 있습니다. (물론 in으로 안되서 꼭 exists를 써야하는 경우도 있습니다.)

 

--- sql4

이건 참고입니다.

select t1.num from test1 t1  --a

minus

select t2.num from test2 t2  --b

 

만약 대용량이고 a와 b의 select 항목이 같다면 sql4가 가장 좋을 듯합니다.

(sql3와 sql4간의 속도차이는 sql4가 좋다고 생각하지만, 정확히는 모르겠습니다.

 아마도 메모리가 많으면 sql4가 빠르고 메모리가 적으면 sql3 정도 일것입니다.)

 

참고로 -.- 님이 말씀하셧듯이 sql에 not이 발상하면 not을 해소할수 있는 법을 생각해보시기 바랍니다. not 조건 또는 !=,<> 은 인덱스를 타지 못할뿐만 아니라. index없이 search가 일어난다 하다라도, 모든 것을 검사해야 존재하지 않는다는 결론이 나오므로 가장 나쁜 케이스만큼의 검사가 일어납니다. 그러나 = or in ,exist등 긍정적인 조건을 쓰면, 한개만 같은게 나온다면 있는것으로 간주하고 끝납니다.

 

뭐든 긍정적인게 좋은겁니다.^^

 

 

장종훈(장종훈)님이 2004-12-15 09:10에 작성한 댓글입니다.
이 댓글은 2004-12-15 09:18에 마지막으로 수정되었습니다.

아... 아직 멀었다는... 쿨럭...ㅡ.ㅜ

또 배우고 갑니다...^^;

민윤기(amgblue)님이 2004-12-15 09:40에 작성한 댓글입니다.

흠.. 제생각은 좀 다른데요...

장종훈님께서 말씀하시듯이

select t1.num from test1 t1

where t1.num not in

(select t1.num from test2 t2 where t1.num = t2.num)

 

이 쿼리보다 무조건

 

select t1.num from test1 t1

where t1.num not in

(select t2.num from test2 t2 )

 

이 쿼리가 낫다고만 볼수는 없습니다.   만약 num 이라는 필드에 인덱스가 있고 분포도가 좋은 상황이라면 위에것이 더 나을수가 있을수도 있지요..

서브쿼리 수행후 나오는결과가 소량이 될수도 있으니까요.. 무조건 위에것이 나쁘다고만 볼수는 없다고 봅니다. 인덱스가 있는 상황에서 아래쿼리에서 rtrim 같은걸로 인덱스를 제외시키고 수행을 하면 또 몰라도.. 어차피 아래쿼리는 양 테이블 풀스캔이니까요... 인덱스가 있는 상황이라면 인덱스테이블 체크후 테이블 풀스캔.. t1 테이블 랜덤액세스 풀스캔이 떨어지는 상황이 되니 꼭 위의 쿼리가 나쁘다고만 볼수는 없습니다..

제 생각은... 그때그때 달라요~~~~ 입니다.... 

 

 

데몬님이 2004-12-15 10:48에 작성한 댓글입니다.
이 댓글은 2004-12-15 10:51에 마지막으로 수정되었습니다. Edit

내 상황에 따라 다른것은 맛습니다

--sql 101

select t1.num from test1 t1   -- a

where t1.num not in

(select t1.num from test2 t2 where t1.num = t2.num)  --b

 

-- sql 102

select t1.num from test1 t1  --x

where t1.num not in

(select t2.num from test2 t2 )  --y

 

sql101과 sql102를 plan 상에서보면 거의 비슷하게 나옵니다. 그러나 내부적인 차이 위에 설명드렸지만 sql101의 내부적인 로직을 보면 O 를 계산해보면

 

sql101은 (t1의 row수) 만큼의 b sql을 수행합니다. b의 sql은 index가 있다면 index를 이용해서 join이 됩니다. 그후 b의 서브쿼리 결과값만큼 비교연산을 하게 됩니다

O=(t1의 row수)*(b의 쿼리시간)+ (t1의 row수)*(b의결과수 평균)

 

sql102는 내부적으로 join으로 변환되게 됩니다. 따라서

a sql 1회+ b sql1회 수행호 메모리상에서 not 조건 때문에 index를 탈수 없으므로 nested join등의 방법으로 존재하지 않는것을 찾습니다.

   ((t1의 row수)x(t2의 row수)번의 비교연산을 하게됩니다.)

 

sql101의 경우  t1의 숫자가 적고 서브쿼리의 결과셋의 유일성에 영향을 받고

sql102의 경우  t1과 t2의 row수에 영향을 받습니다.

 

t1의 row수는 동일하므로

sql101이 빠르려면 서브쿼리의 결과셋이 적거나 num이 단일pk일경우

       (서브쿼리의 결과값평균을 n이라고 하면 O의 n승의 수행시간)

sql102가 빠르려면 t2의 row수가 적어야한다는 결론이 나옵니다

       ( t2의 row수를 m 이라고 O*n 의 수행시간)

 

--전산학 기초까지 나왔는데 서브쿼리가 유일성을 유지한다면 sql101이 빠르고

   그렇지 않다면 sql102가 빠르다는 결론이 나옵니다.

  그리고, 동시접속자가 많아서 동일한 sql이 동시수행되는 때가 많은경우에는 sql102 

  가 더빠르겟지요.

  또한 대용량 데이터베이스에서는 당연히 sql102가 빠릅니다.

  sql101이 빠른경우가 있긴하겟지만 극히 드물다는 결론이 나옵니다.

 

장문에 되어버렸는데 sql 튜닝에 도움이 되셨기를 바랍니다.

 

 

 

 

 

장종훈(우연을가장한인연)님이 2004-12-15 11:27에 작성한 댓글입니다.

흠... 전 두 쿼리 다 안좋다 생각하고요...

근데 아래쿼리가 무조건 더 빠르다 말씀을 하셨길래..

 

그때그때 다르다고 말씀드린겁니다...

not exists 나 minus로 하는게 더 낫다고 보고 있습니다...

 

그리고 제가 오라클을 테스트할수가 없어서.. 다른 디비를 써서 어쩔수없이

테스트는 못해보기때문에 모 다른것은 해볼수가 없지만...

상황에따라 다르다고 말씀을 드린것이고..

님께서도 상황에 따라 다르다고 보신다고 하셨는데

결론은 아래쿼리가 더 빠르다고 결론을 지으시는건 약간 모순이 있지 않나생각되네요..

 

딴지 거는건 아니고요...  그럼 즐팅~~

 

데몬님이 2004-12-15 11:47에 작성한 댓글입니다. Edit

위와는 약간 다른 얘기일 수도 있지만..

 

기본적으로 in 을 사용한다는 것은 서브쿼리를 공급자로 사용해보겠다는 뜻입니다.

다시 말하면 서브쿼리가 먼저 수행되어 메인쿼리를 제한하겠다는 것이죠.

또한 exists를 사용하겠다는 것은 서브쿼리를 확인자로 사용하겠다는 뜻입니다.

메인쿼리를 먼저 수행하면서 서브쿼리 조건에 합당한지 체크해보겠다는 것이죠.

 

서브쿼리가 먼저 수행되게 하려면 서브쿼리에서 메인쿼리의 컬럼을 사용하지

않아야 합니다. 그래야 메인쿼리로부터의 종속성을 끊을 수 있겠죠.

따라서 in을 사용하면서 메인쿼리의 컬럼을 사용하는 것은 문제가 있다는 것입니다.

a.col in (select b.col1 from ...) 이런 식의 문장에서 벌써 메인쿼리와 서브쿼리는

연결된 것이지요.. 근데 where절에 또 where a.col1 = b.col1 이런식으로 기술하는

것은 애초의 in을 사용하는 목적에 위배된다는 것입니다.

in 은 잘써도 공급자로 쓰기가 어렵습니다.. 그런데 여기에다 불필요한 조인조건까지

넣는다면 더더군다나 목적을 달성하기 힘들겠죠..

 

부정형일때는 메인쿼리나 서브쿼리의 분포도등에 따라 많이 달라지겠지만..

not exists로 필터처리하는 것이 일반적이며..

(메인쿼리의 컬럼중에 서브쿼리에 존재하지 않는지 체크하는 경우가 많으므로)

때에 따라 not in이 유리한 경우도 있습니다.

(부정형 해쉬조인이나 머지조인형태가 유리할때)

 

또한가지 메인쿼리가 먼저 수행되면서 서브쿼리가 나중에 수행되는 형태에서

유리한 방법은 아우터조인을 이용하는 방법입니다. (1:1, M:1형태에서만 가능)

 

select t1.num

from test1 t1

       ,test2 t2

where t1.num = t2.num(+)

and t2.num is null

 

not exists와 유사한 형태지요.. (Nested Loop형태가 유리할 때)

 

상황에 따라 유리한 방법을 사용하는 것이 좋을 것입니다.

ccr님이 2004-12-15 15:50에 작성한 댓글입니다.
이 댓글은 2004-12-15 15:54에 마지막으로 수정되었습니다. Edit
[Top]
No.
제목
작성자
작성일
조회
21055[질문]rownum에 대하여 [3]
이솔
2004-12-14
3520
21054쿼리좀 봐주세요 [2]
왕초보
2004-12-14
1004
21053설치된 오라클의 문자종류를 바꾸는 방법이 있나여? [1]
이인수
2004-12-14
1678
21050쿼리좀 도와 주세요. 감사합니다. [11]
unimeek
2004-12-14
3831
21049정렬이 안되요..ㅠ.ㅠ. [1]
초보중초보
2004-12-14
1682
21048특정 기간의 날짜를 전부 다 입력하는 방법은? [2]
2004-12-14
1673
21047쿼리문 구현 help [2]
초보중초보
2004-12-14
1278
Valid XHTML 1.0!
All about the DATABASE... Copyleft 1999-2024 DSN, All rights reserved.
작업시간: 0.021초, 이곳 서비스는
	PostgreSQL v16.4로 자료를 관리합니다