Parse Call 이란

흔히 말하는 Parsing = Parsing(파싱, parse count(total)) + Parse call(최적화, parse count(hard)) 를 말함.
이를 분리해야 하는 이유는

  1. Parse call 은 항상 발생 하지 않는다.
  2. 최적화를 위해서 반드시 parse call 이 필요한 것은 아니다.
  3. Parsing 을 위해서 반드시 parse call 이 필요한 것은 아니다.
  4. Parsing 과 최적화는 parse call 뿐만 아니라 execute call 단계에서도 발생

  • Parse count(total) : 오라클커널에 의해 수행된 parse call 횟수 = SQL 수행 횟수
    Bind variable test 시에는 PL/SQL cursor cache 효과(11g 이상 시만 )에 의해서 parse call 획기적으로 줄어듦
  • Parse count(Hard) : 오라클이 문장을 최적화 한 횟수 = 최적화 횟수
  • 문장에 대한 최적화(Parse count(hard)) 없이 parse call(parse count(total) 수행 가능
  • 루프 내의 첫 번째 실행 시에, 오라클은 해당 문장에 대한 파싱 및 최적화 수행 후, 라이브러리 캐시 적재
  • 루프 내의 두 번째 실행 시에, 오라클은파싱 및 최적화를 시작하기 전에 라이브러리 캐시를 검색하고, 동일 문장 존재 시, 최적화를 수행 하지 않고 재사용

cursor authentication
: 자식 커서의 내용을 비교 (동일 오브젝트여부/동일 권한여부/동일 옵티마이져 여부)

커서 캐싱

: 커서 캐싱을 디폴트(50)과 0으로 설정 후, dbms_sql 캐시지를 이용한 명시작 parse 와 execute call 수행


fori in 1..1000 loop
		m_cursor := dbms_sql.open_cursor;
		dbms_sql.parse(
			m_cursor,
			'select n1 from t1 where id = :n',
			dbms_sql.native
		);
		dbms_sql.define_column(m_cursor,1,m_n);
		dbms_sql.bind_variable(m_cursor, ':n', i);
		m_rows_processed := dbms_sql.execute(m_cursor);
		ifdbms_sql.fetch_rows(m_cursor) > 0 then
			dbms_sql.column_value(m_cursor, 1, m_n);
		end if;
		dbms_sql.close_cursor(m_cursor);
	end loop;

    • Parse count(hard) 수치(=최적화 횟수)는 작다 ==> 루프 내 문장 재사용
    • 세션 캐시에 따른 커서에 액세스 방법 차이가, 경합 차이 발생 시킴 ( 래치 gets 수치 차이 유발 )
      세션 커서 캐시 : SQL 자주 수행 = 문장 커서에 KGL lock 설정, 세션 메모리 내에 state object 를 생성 후, 해당 커서와 연결
      라이브러리 검색 없이 문장 사용

커서 캐싱 동작 방식

  1. 첫 번째 실행 시 최적화 수행
  2. (첫 수행 세션과 다른 세션도 가능함)두 번째 실행 시 인증 수행 ( cursor authentication = child cursor 비교작업 )
  3. 세 번째 실행이 완료된 이후에 캐싱
  4. 이후부터 캐싱된 정보 사용
    세션 커서 캐시에 존재한다는 것은 parse call 시에(문장 execute 시에) 어떠한 Parsing (최적화)도 수행 하지 않는다는 것 의미

커서 홀딩

문장을 자주 사용한다면, 커서 변수 선언, 원하는 만큼 오랫동안 커서를 open 하는것이 바람직


m_cursor := dbms_sql.open_cursor;
	dbms_sql.parse(
		m_cursor,
		'select n1 from t1 where id = :n',
		dbms_sql.native
	);

	dbms_sql.define_column(m_cursor,1,m_n);

	fori in 1..1000 loop
		dbms_sql.bind_variable(m_cursor, ':n', i);
		m_rows_processed := dbms_sql.execute(m_cursor);

		ifdbms_sql.fetch_rows(m_cursor) > 0 then
			dbms_sql.column_value(m_cursor, 1, m_n);
		end if;
	end loop;

	dbms_sql.close_cursor(m_cursor);

  • 래치 획득 수치가 추백번 정도 ( VS 이전 수천번 )

execute call 시 파싱과 최적화 발생 할 경우
: PL/SQL 최적화로 인한 홀딩(Holding) 커서의 부작용

  1. 홀딩 커서는 내부적으로 라이브러리 캐시 내의 자식 커서와 부모 커서와 연결되어 있다.
  2. 라이브러리 캐시 메모리 필요, 자식 커서의 대부분을 메모리에서 제고함(세션이 커서 홀딩하여도 )
  3. 이 시점에 문장을 재수행 하면, parse count(total) = sql 수행 횟수 통계 수치는 증가하지 않음에도 불구하고 Miss in library cache during exeucte 가 기록되고,
  4. parse count(hard)=최적화 통계가 증가한다.
    결과적으로 parse count(total) < parse count(hard )