우리가 프로시져를 쓸 때 다음과 같은 구문을 자주 사용한다.

IF ((SELECT COUNT(*) FROM TEST_TAB WHERE STATUS = 'S') > 0)
     UPDATE TEST_TAB      SET STATUS = 'R'     WHERE STATUS = 'S'

위의 구분은 업데이트 대상이 존재하는지 먼저 SELECT해 보고,
대상이 있을 경우에만 UPDATE 한다는 뜻이다.
그렇다면, 왜 SELECT 테스트를 먼저 수행하는 것이 바로 UPDATE부터 수행하는 것보다 비용이 적을까?

(위의 예에서 테스트 대상 테이블은 26,000개의 레코드가 들어있었다.)
업데이트 대상이 존재할 경우, SELECT와 UPDATE를 둘 다 해야 하기 때문에
무조건 UPDATE부터 하는 것보다 분명히 더 비용이 비쌀 것으로 예상된다.

그렇다면... 업데이트 대상이 존재하지 않을 경우는 어떨까?
SELECT를 함으로서 UPDATE를 해보지 않아도 되기 때문에 더 적은 비용이 드는 걸까?

SELECT COUNT(*) FROM IP_TEST_TAB    WHERE STATUS = 'S' -- 1
UPDATE TEST_TAB   SET STATUS = 'R'     WHERE STATUS = 'S' -- 2

STATUS 컬럼이 'S'인 레코드가 한개도 없는 (즉, 업데이트 대상이 0개인) 상황을 만들어 놓고 위의 두가지 해 보았다. 프로필러에 나타난 결과는 다음과 같다.

1번 SELECT 문 : CPU(235), READ(1761), WRITE(0), DURATION(236)
2번 UPDATE 문 : CPU(0), READ(1186), WRITE(0), DURATION(16)

즉, 대상 데이터가 한개도 없는 경우에도 바로 UPDATE부터 실행시키는 것이 훨씬 비용이 적다는 것이다.

그렇다면, SELECT를 해서 UPDATE할 데이터가 있는지 체크해보지 않고 직접 UPDATE부터 하는 것이 더 좋은 방법일까??
아래의 테스트를 해 보자.
-- 세션 1, 2에서 아래의 SQL을 순서대로 실행
BEGIN TRAN
UPDATE TEST_TAB  SET STATUS = 'R' WHERE STATUS = 'S'
STATUS 컬럼을 모두 'R'로 변경한 상태에서 위의 SQL을 두 세션에서 순차적으로 실행시켜보자. 나중에 실행된 세션에서 LOCK이 걸리는가? 테스트해보면 LOCK이 걸리지는 않는 것을 알 수 있다.

UPDATE문을 실행시킬 때는 EXCLUSIVE LOCK이 걸린다. 즉, UPDATE문은 동시에 두개가 실행될 수 없다는 뜻이다. 그런데, 위의 테스트를 통해 LOCK 이 걸리는 것은 실제 변경되는 RECORD가 발생할 때 부터라는 것을 알 수 있었다. 요약하면, "UPDATE문을 실행했더라도 WHERE에 의해 영향을 받는 ROWS가 없는 경우는 LOCK이 걸리지 않는다."

상기 테스트를 종합해 볼 때... 아래와 같은 결론을 내릴 수 있다.

1. 어떤 경우에도  업데이트 전에 SELECT 테스트를 수행하는 것이 비용이 더 비싸다.
2. SELECT 테스트 없이 직접 UPDATE를 날리더라도 변경 대상 레코드가 없는 경우에는 EXCLUSIVE LOCK이 걸리지 않는다.
※ 따라서 SELECT 테스트 없이 직접 UPDATE부터 날리는 것이 더 낫다.
Posted by kuaaan
,


사랑합니다. 편안히 잠드소서