real my sql - Stored Function

존스노우·2024년 7월 28일
0

REAL MY SQL

목록 보기
5/5

MYSQL Function

  • function vs index optimizaion

DETERMINISTIC VS NOT DETERMINISTIC

  • MySQL Server의 stroed Function은 반드시 둘 중 하나의 속성을 가지게 됨
  • DETERMINISTIC
  • 한글로 확정적이라 해석 됨
  • 입력이 동일하면 언제 실행하든지 관계없이 동일 한 출력
  • 함수의 호출 시점마다 참조하는 테이블 데이터가 달라지는 경우도 생각해 볼 수 있음
  • 여기서 입력이라하면 함수의 인자뿐 아니라 함수가 참조하는 데이터도 같이 포함 한다고 이해하자
  • DETERMINISTIC 펑션이라 하더라도 참조하는 테이블이 데이터가 달라지면
  • 입력이 달라지므로 출력이 달라짐
  • ex ) 오늘 가입한 사용자의 수를 가져오는 함수를 만들었을 때
  • stored function이 실행되는 도중에도 사용자의 가입은 꼐속 진행되기때문에
  • 이 함수는 호출할때마다 결과가 달라질 수 도 있다
  • 하지만 이 때 사용자 테이블의 레코드가 달라지는 것도 입력이 달라지는 것으로 해석하기 때문에
  • MYsql 서버에서 셀럭터를 포함해서 하나의 statement는 반드시 시작 시점의 스냅샷을 보도록 구현 됨
  • 그래서 mysql 서버에서 실행되는 query 문장 하나는 동일한 데이터 상태를 보게 됨
  • 그래서 하나의 문장내에서 stored function이 여러번 호출된다고 하더라도 테이블의 데이터는
  • 해당 시점의 스냅샷을 보기 때문에 함수의 인자만 동일하다면 입력이 달라지지 않는 것으로 볼 수 있다.
  • 지금까지 설명한 것과 반대로 입력이 동일하더라도 호출되는 시점에 따라서 결과가 달라질 수 있는
  • 비확정적 이라하고 NOT DETERMINISTIC 키워드 로 정의

정리

확정적 함수

  • 같은 입력을 넣으면 항상 같은 결과가 나옴
  • 예를 들어, 숫자를 두 배로 만드는 함수는 항상 같은 결과
  • 주의할 점은, '입력'이라고 할 때 함수에 직접 넣는 값뿐만 아니라 함수가 사용하는 테이블의 데이터도 포함된다
  • MySQL은 하나의 쿼리 문장이 실행될 때, 그 순간의 데이터 상태를 '사진 찍듯이' 저장해둡니다. 이걸 '스냅샷'이라고 해요
  • 같은 쿼리 안에서 함수를 여러 번 호출해도, 항상 같은 데이터를 보게 됨

  • function 1 , function 2 함수 정의
SELECT * FROM tab WHERE id=func1();
SELECT * FROM tab WHERE id=func2();

SELECT @func1_called , @func2_called;

@func1_called = 3
@func2_called = 12


CREATE
DEFINER=root@ 'localhost'
FUNCTION func1() RETURNS INTEGER
DETERMINISTIC SQL SECURITY INVOKER
BEGIN
   SET @func1_called = INNULL(@func1_called,0) +1;
   RETURN 1;
 END ;;
 
 
 CREATE
DEFINER=root@ 'localhost'
FUNCTION func2() RETURNS INTEGER
NOT DETERMINISTIC SQL SECURITY INVOKER
BEGIN
   SET @func2_called = INNULL(@func2_called,0) +1;
   RETURN 1;
 END ;;
 
 
  • 확정 함수와 비확정 함수 정의
  • 변수의 값은 단순히 1씩 증가하는 함수
  • tab이라는 테이블에서 id 컬럼의 값이 fun1 과 fun2 함수의 결과 값이랑 동일한 레코더 찾는 쿼리 실행해보자
  • 두 쿼리 실행 결과 값 중요 X 쿼리 실행 결과
  • func1_called 와 fun2_called 가 어떻게 바뀌었는지 중요
  • 각 3 / 12번 호출된걸 알수 있다
  • 호출횟수가 많다? 그만큼 많이 실행 됬다 -> 함수가 사용된 쿼리 처리시 실행ㅅ히간보다 cpu 또는 메모리 사용량이한 4배정도 더 많이 소요됬다.

정리

  • func1: 확정적 함수 (Deterministic) / func2: 비확정적 함수 (Not Deterministic)
  • 두 함수는 거의 똑같아요. 호출될 때마다 각각의 카운터(@func1_called, @func2_called)를 1씩 증가시키고, 항상 1을 반환

SELECT FROM tab WHERE id=func1();
SELECT
FROM tab WHERE id=func2();

  • 각 몇번 호출 되었나? 3 / 12
  • func2(비확정적 함수)가 func1(확정적 함수)보다 4배나 더 많이 호출되었다는 거
  • func2를 사용한 쿼리가 더 많은 시간과 자원(CPU, 메모리 등)을 사용했다는 걸 의미
  • 비확정적 함수(Not Deterministic)는 확정적 함수(Deterministic)보다 더 자주 호출될 수 있으며, 이는 쿼리 성능에 큰 영향을 미칠 수 있다

DETERMINISTIC 여부에 따른 작동 차이

  • 두 함수의 차이가 발생하는 원인을 찾아 보자

  • 확정 함수 func1 첫번재 쿼리는 기본키 타입을 const 타입으로 접근 함

  • 테이블의 레코드를 1건만 읽었다는 것 의미 매우 빠르게 처리되었다는 것을 의미

  • 실행 계획 하단의 노트에 명시된 query에서도 where 절의 func1 함수 호출이 없어진것을 알 수 있따

  • 이는 최적화 되어서 함수 호출 부분 자체가 사라짐의미

  • 두번째 쿼리는 실행계획 타입이 all 이라는것을 알수 있다

  • 이거는 쿼리가 풀테이블 스캔으로 처리되었다는 것을 의미

  • 실행 계획 하단의 노트에 표시된 쿼리에서 func2 함수 호출코드가 남아 있다.

  • 이번 실행 계획에서는 확정되지함수가 풀스캔을 하는 심각한 문제를 가지고 있는 것 확인 가능

  • 쿼리 실행 계획이 인덱스를 사용하지 못하고 풀 테이블 스캔으로 바뀌었기 때문 (호출 횟수가 많이 높은 이유)

정리

확정적 함수(func1) 사용 쿼리

  • 데이터베이스가 아주 똑똑하게 동작
  • 단 한 번의 검색으로 원하는 데이터를 찾았어요 (const 타입)
  • 함수 호출 부분을 아예 없애버렸어요. 이걸 '최적화'

비확정적 함수(func2) 사용 쿼리

  • 데이터베이스가 조금 둔하게 동작
  • 모든 데이터를 하나하나 다 뒤짐 (ALL 타입, 풀 테이블 스캔)
  • 함수를 계속 호출하면서 검색

왜 이렇게 다를까?

  • 확정적 함수는 결과를 예측할 수 있어서 데이터베이스가 똑똑하게 처리
  • 비확정적 함수는 결과를 예측할 수 없어서 데이터베이스가 모든 경우를 다 확인

NOT DETERMINISTIC 최적화 이슈

  • 왜 이런 문제가 생기지?
  • 실행하는 시점에 따라서 다른 값을 반환할 수 있다는 것 때문에 이 모든 문제가 발생함
  • EX) 레코드 건수가 10건인 테이블에서 WHERE 조건절이 ID 값인
  • stored function 호출 결과값과 동일한 레코드를 찾으려고 하는 것 인데
  • Not Determinisic 속성의 fuynction2 함수는 레코더를 매번 비교할 때마다
  • fuction2 함수 결과값이 매번 달라짐
  • 그래서 MySql 서버의 옵티마이저는 function2함수의 결과 값을 상수로 취급하지 못함
  • 그래서 테이블의 레코더를 한 건씩 읽어서 비교할 때마다 function2 함수를 실행해서
  • 결과 값을 매번 새롭게 가져와서 비교를 수행하게 됨
  • Not Deteministic 함수를 where 조건절의 비교값으로
  • 사용하게 되면 Mysql 서버는 해당 컬럼에 인덱스가 있다하더라도 인덱스가 있더라도 인덱스 최적화 못해 풀 테이블 스캔으로 처리됨

Not Deterministic 효과

  • mysql 서버에서는 not Deterministic 속성이 Stored function에만 적용되는게 아님
  • mysql 서버는 다양한 built-in 함수들이 있음 (Not Deterministic 으로 정의된 함수들 속성을 상속받음)
  • RAND() , UUID() , SYSDATE(), NOW()
  • 위 예시들은 where조건절에 사용되면 비교되는 모든 컬럼의 인덱스를 효율적으로 사ㅓ용하지 못하게 되므로 똑같이 주의 필요

Not Deterministic 예외

  • now 와 sysdate함수는 조금 예외적인 성격을 가지고 있음
  • 위 예 제는 tab 테이블에서 10건의 레코드만 줘야 하는데 now 함수 의 결과값과
  • sysdate 결과값 가져오는 쿼리
  • slip 함수를 이용해서 레코드 끈 단위로 1 초씩 슬립하도록 쿼리를 조금 변경함
  • now 함수의 결과값은 모두 동일함 쿼리가 시작된 시점만 반환
  • sysdate는 첫번재는 now함수와 동일한 결과값을 반환하지만
  • 그뒤로는 슬립 패턴 1초씩 뒤로 밀려있음
  • 둘다 not Deterministic 이긴 하지만
  • now 함수는 하나의 문장안에서 deferministic처럼 인식되도록 구현되있음
  • 반면 sysdate는 not deterministic처럼 레코드 끝단위로 매번 새로 호출됨
  • 그 결과 매번 결과값이 달라짐
  • 그래서 create_at = now() (인덱스 적용) 쿼리 최적 실행 가능
  • sysdate 결과값과 비교하는 경우 full table scan을 한다
  • 의외로 이 둘의 차이를 잘모르는 개발자가 많음
  • sysdate-is-now 설정을 mysql 서버에서 옵션을 넣어주면 now 함수와 같은방식으로 실행되게함

mysql stored function 사용시 주의사항

  • mysql server에서 stored function 을 not deterministic 이 기본 속성
  • stored function 생성할때 deterministic 옵션을 별도로 설정 해줘야 됨
  • Stored Function 정의시 많이 실수하는 부분인 define 부분과
  • Sql security 속성도 정확히 이해하고 명시하는걸 권장

정리

NOT DETERMINISTIC 최적화 이슈:

NOT DETERMINISTIC 함수는 실행할 때마다 다른 결과를 반환할 수 있다

  • 이로 인해 MySQL 옵티마이저가 효율적으로 쿼리를 최적화하지 못함
  • 예를 들어, WHERE 절에서 NOT DETERMINISTIC 함수를 사용하면 인덱스를 사용할 수 없게 되어 전체 테이블 스캔이 발생

NOT DETERMINISTIC 효과

  • 이 속성은 Stored Function뿐만 아니라 일부 내장 함수(RAND(), UUID(), SYSDATE(), NOW() 등)에도 적용
  • 이런 함수들을 WHERE 절에 사용하면 인덱스를 효율적으로 사용하지 못함

NOT DETERMINISTIC 예외

  • NOW()와 SYSDATE() 함수는 약간 다르게 동작
  • NOW()는 쿼리 시작 시점의 시간을 반환하고, 쿼리 내에서 일관된 값을 유지
  • SYSDATE()는 매 호출마다 현재 시간을 반환
  • 따라서 NOW()는 인덱스를 사용할 수 있지만, SYSDATE()는 전체 테이블 스캔을 유발

MySQL Stored Function 사용 시 주의사항

  • MySQL에서 Stored Function은 기본적으로 NOT DETERMINISTIC
  • DETERMINISTIC으로 설정하려면 함수 생성 시 명시적으로 지정 해야 함
  • DEFINER와 SQL SECURITY 속성도 정확히 이해하고 설정해야 함
profile
어제의 나보다 한걸음 더

0개의 댓글