36.6. 휘발성에 따른 함수 분류

모든 함수는 휘발성이라는 속성에 따라 VOLATILE, STABLE, IMMUTABLE 함수로 구분 된다. CREATE FUNCTION 명령으로 함수를 만들 때, 이 속성을 따로 지정하지 않으면, 기본값으로 VOLATILE 속성이 지정된다. 이 휘발성 속성은 쿼리 최적화기에서 그 함수를 어떻게 처리할 것인가에 대한 약속이다.

가장 좋은 쿼리 성능을 얻으려면, 자신이 만든 함수에 대해서 가장 적당한 휘발성 분류를 지정해 주는 것이다.

의도되지 않은 결과를 초래할 수 있는 함수라고 생각되면 그 함수는 반드시 VOLATILE 함수로 만드는 것이 좋다. 그렇게 해야 최적화기가 실행 계획을 만들 때 의도되지 않은 엉뚱한 결과를 만들지 않는다. 물론 그 함수의 내용이 명확하고 다른 부작용도 없다고 확신해도, random(), currval(), timeofday() 이런 함수 같이 변환값이 항상 다른 함수를 사용하는 경우라면, VOLATILE 함수로 만들어야 한다.

다른 중요한 예로, current_timestamp 계열 함수를 사용한다면, STABLE 함수로 만들어도 괜찮다. 왜냐하면, 이 계열 함수들은 하나의 트랜잭션 내에서는 항상 같은 값을 반환하기 때문이다.

일반적인 대화형 쿼리에서는 STABLE 함수나, IMMUTABLE 함수 사이 차이가 별로 없다. 어차피 그 쿼리가 실행 될 때 둘 다, 한 번은 그 함수 처리를 위한 비용 계산을 하기 때문이다. 가장 큰 차이점은 그 실행 계획이 저장되거나 재사용될 경우다. IMMUTABLE 함수로 만들어, 그 함수의 반환값이 상수화 되어 실행 계획이 작성되고, 그 상수값이 그대로 재사용된다면, 의도하지 않게 나쁜 실행 계획이 될 수도 있다. 미리 준비된 구문 prepared statement 을 사용하는 경우나, PL/pgSQL 같이 그 실행 계획이 미리 저장되는 프로시져 언어로 작성된 함수에서 이런 위험이 있을 수 있다.

SQL이나 표준 프로시져 언어로 작성된 함수에서 주의해야 할 두번째 사항은 그 함수가 사용되는 쿼리가 반환하는 자료의 가시성 부분이다. VOLATILE 함수는 항상 상황에 맞는 결과를 반환하지만, STABLE, IMMUTABLE 함수는 그렇지 않다. 이 처리 방식은 MVCC (13장 참조) 스냅샷 작동방식을 사용해서 구현되었다. STABLE, IMMUTABLE 함수는 처음 쿼리가 호출 될 때 스냅샷을 찍고, VOLATILE 함수는 해당 쿼리에서 사용될 때 마다 스냅샷을 찍는다.

참고: C 언어로 함수를 만드는 경우는 이 스냅샷 관리를 자체적으로 할 수도 있지만, 일반적으로 그 모듈을 이용하는 함수를 만들 때, 그 함수의 휘발성을 지정하는 것이 좋은 방법이다.

이런 스냅샷 처리 방식 때문에, STABLE 함수에서는 그 해당 자료가 다른 세션에 의해 변경 되었다 하더라도 안전한 SELECT 작업을 할 수 있다. PostgreSQLSTABLE 함수 안에서 사용되는 명령들은 스냅샷 처리를 하여, 그 세션이 보아야 할 자료만 각각 볼 수 있다.

또한 이 스냅샷 처리 방식의 SELECT 작업은 IMMUTABLE 함수에서도 그대로 적용된다. 하지만, 그 결과는 STABLE 함수와 달리 의도되지 않은 것일 수 있다. 왜냐하면, 해당 테이블의 자료가 다른 세션에 의해 바뀔 수 있기 때문이다. 그럼에도 불구하고, PostgreSQL 이런 문제점에 대해서 사용자 몫으로 남겨둔다. IMMUTABLE 함수에서도 SELECT 작업을 할 수는 있다.

일반적인 오류는 IMMUTABLE 함수의 반환값이 서버 환경 설정 매개 변수값에 영향을 받는 경우다. 예를 들어, 시간을 처리하는 함수는 TimeZone 설정값에 의존적이다. 안전을 위해, 이런 함수들은 STABLE 함수로 만든다.

참고: PostgreSQL에서는 자료 변경을 방지하기 위해, STABLE 또는 IMMUTABLE 함수인 경우 데이터베이스 처리 작업으로 SELECT 명령만 허용한다. (하지만 이처리가 완벽하지는 않다. VOLATILE 함수의 내용 가운데, STABLE, IMMUTABLE 함수를 사용하는 구문이 있고, 이런 함수들의 반환값이 데이터베이스가 변경 된 부분에 대한 반영을 제대로 했는지를 모두 꼼꼼하게 검사하지는 못했다.)