데이터베이스 서버와 클라이언트 간 연결상태를 유지하면 서버 자원을 낭비하게 되므로 동시 사용자가 많은 OLTP 환경에선 SQL 수행을 마치자마자 곧바로 연결을 닫아주는 것이 바람직하다.
연결 요청에 대한 부하는 쓰레드 기반 아키텍처보다 프로세스 기반 아키텍처에서 더 심하게 발생한다.
전용 서버 (Dedicated Server) 방식으로 오라클 데이터베이스에 접속하면 사용자가 데이터베이스 서버에 연결 요청을 할 때마다 서버 프로세스가 생성된다.
공유 서버 (Shared Server) 방식으로 오라클 데이터베이스에 접속하면 사용자 프로세스는 서버 프로세스와 직접 통신하지 않고 Dispatcher 프로세스를 거친다.
SQL 수행을 마치자마자 곧바로 연결을 닫는다는 건 쿼리를 날릴 때마다 연결을 했다가 끊었다가 한다는 뜻이다. 연결을 한다는 것은 서버 프로세스를 새로 실행한다는 뜻이므로, 연결을 하는 자체에 큰 오버헤드가 발생한다. 따라서 SQL을 마치자마자 연결을 끊는 것보단, 또 쿼리가 들어올 수도 있으니 연결을 열어두는 것이 좋다.
일반적으로 context switch는 스레드보다 프로세스에서 오버헤드가 크다.
DBMS 는 데이터를 블록 단위로 읽고 쓴다. SQL 성능을 좌우하는 것은 DBMS가 처리하는 블록의 수이다.
DBMS 는 익스텐트 단위로 테이블에 공간을 할당한다.
익스텐트 내 블록들은 연속하지만, 세그먼트 내 익스텐트는 연속하지 않는다.
세그먼트를 구성하는 익스텐트들은 여러 데이터 파일에 흩어져 있을 수 있다.
오브젝트는 테이블이나 뷰, 인덱스 등 실체가 있으며 독립적으로 존재했을 때 의미가 있는 저장공간이다. Oracle은 한 익스텐트에 속한 모든 블록을 단일 오브젝트가 사용하지만, SQL Server에서는 2개 이상 오브젝트가 나누어 사용할 수도 있다.
정답/해설“버퍼 캐시 블록을 갱신하기 전에 변경사항을 먼저 로그 버퍼에 기록 해야 하며, Dirty 버퍼를 디스크에 기록하기 전에 해당 로그 엔트리를 먼저 로그 파일에 기록해야 한다.”
DBWR가 dirty 버퍼를 디스크에 저장하기 전에 Redo 로그를 남기는 (= Redo 버퍼를 비우고 Redo 로그 파일에 저장하는) 이유는 나중에 복구하기 위해서이다.
이렇게 하지 않으면(커밋 여부를 기록하지 않고 데이터 파일에 바로 기록하게 되면) 나중에 redo 로그를 보고 복구된 (roll-forward) 캐시에서 커밋되지 않은 트랜잭션을 undo 할 수가 없다. (rollback)
이렇게 데이터 파일에 쓰기 전에 로그부터 남기는 것을 Write Ahead Logging 방식이라고 한다.
/*+ append */
힌트를 사용하면 Insert 시 DB 버퍼 캐시를 거치지 않고 디스크에서 직접 쓴다.데이터 블록을 읽으면 DB 버퍼 캐시에 올라간다.
나중에 찾을 때 해시버킷에서 찾아서 쓴다.
DB 버퍼 캐시는 LRU 알고리즘으로 관리된다.
/*+ append */
힌트를 사용하면 direct-path로 INSERT 할 수 있다. direct-path 란 데이터가 지금 있는 공간을 사용하지 않고 그 바로 뒤에 새로 추가하는 것을 말하며, 버퍼 캐시를 우회해서 데이터 파일에 바로 쓰여진다. 그 결과로 direct-path INSERT는 기존 INSERT 보다 훨씬 빠르다.
클러스터링 팩터가 좋다는 것은 인덱스로 찾아 들어갔을 때 leaf가 같은 블록에 모여있다는 것이다.
그렇다면 인덱싱 한 칼럼의 특정 범위로 찾을 수 있는 테이블의 row들은 한 블록에 모여있을 가능성이 크다.
위의 경우 2022년 10월 13일부터 15일까지에 해당하는 데이터는 한 블록에 모여있을 것이다. 이때 같은 블록을 여러 번 읽으므로, 그 블록을 pin 해두면 I/O 성능이 좋아진다.
Table Full Scan 한 데이터 블록은 LRU end에 위치하기 때문에 버퍼 캐시에 오래 머물지 않는다. 오라클은 tabel full scan 에서 찾아진 블록들을 LRU end에 둔다. 왜냐면 full scan은 아주 가끔 있는 일이라고 판단해서 다른 블록보다 캐싱될 확률이 적다고 생각하기 때문이다.
참조
출처
Response Time = Service Time + Wait Time = CPU Time + Queue Time
1회 발생한다. custno
는 바인드 변수이기 때문에, 1000을 넣어도 2000을 넣어도 같은 쿼리, 같은 실행 계획으로 실행된다.
따라서 해당 SQL문은 Hard Parsing이 1회 실행된다.
1. 첫 번째 수행될 때 각각 하드파싱을 일으키고, 다른 캐시 공간을 사용할 것이다.
SQL문을 실행하면 하드 파싱 되어 SGA 내 공유 풀, 공유 풀 내 라이브러리 캐시에 저장된다.
다만 이는 SQL문으로 찾을 수 있기 때문에, 같은 SQL문이라도 토씨 하나 틀리면 다른 문이 된다.
따라서 위 세 SQL문은 각각 하드파싱이 반복된다.
바인드 변수를 쓰는 이유는 캐싱된 SQL을 재사용하기 위함이다. 수행빈도가 낮으면 어차피 캐시 버퍼에서 빠지게 돼서 굳이 바인드 변수를 안 써도 된다.
값의 분포가 균일하지 않다면 바인드 변수를 쓰는 게 더 느릴 수도 있다. 옵티마이저는 값이 균일하게 분포돼있다는 가정하에 최적하를 수행하기 때문이다.
조건절이 복잡한 거랑은 상관 없다. 비교문은 바인드 변수를 쓰는 것이 일반적으로 좋다.
불변이면 애초에 바인드 변수를 쓰지 못한다.
Dynamic SQL은 라이브러리 캐시랑은 상관 없다.
애플리케이션 커서 캐싱이 안 되는 것이다.