<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
	<id>https://dbstudy.co.kr/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Oracle</id>
	<title>DB스터디 - 사용자 기여 [ko]</title>
	<link rel="self" type="application/atom+xml" href="https://dbstudy.co.kr/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Oracle"/>
	<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/%ED%8A%B9%EC%88%98:%EA%B8%B0%EC%97%AC/Oracle"/>
	<updated>2026-05-08T13:33:06Z</updated>
	<subtitle>사용자 기여</subtitle>
	<generator>MediaWiki 1.39.10</generator>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%97%AD_%EC%9D%B8%EB%8D%B1%EC%8B%B1(Inverted_Index)&amp;diff=1713</id>
		<title>역 인덱싱(Inverted Index)</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%97%AD_%EC%9D%B8%EB%8D%B1%EC%8B%B1(Inverted_Index)&amp;diff=1713"/>
		<updated>2026-03-13T02:13:40Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 역 인덱싱(Inverted Index)의 작동 원리 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 역 인덱싱 (Inverted Index)  ==&lt;br /&gt;
* Oracle Text(Context Index)가 바로 &#039;역 색인(Inverted Index)&#039; 원리를 이용한 기술임.&lt;br /&gt;
* 일반적인 B-Tree 인덱스가 책의 &#039;목차&#039;라면, 역 인덱스는 책 뒷부분의 **&#039;찾아보기(색인)&#039;**와 같습니다. &lt;br /&gt;
* 특정 단어가 어느 페이지(RowID)에 있는지 미리 지도로 그려두는 방식임.&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 역 인덱싱(Inverted Index)의 작동 원리 ===&lt;br /&gt;
* 예를들어 5천만건의 대용량 테이블에 Context Index를 생성하면 내부적으로 다음과 같은 구조의 보조 테이블(주로 `$I` 테이블)이 생성됩니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;:&lt;br /&gt;
| 토큰(Token) | 문서 ID 리스트 (DocID / RowID) |&lt;br /&gt;
| --- | --- |&lt;br /&gt;
| **KIM** | Row1, Row5, Row10... |&lt;br /&gt;
| **TEST** | Row1, Row2, Row8, Row10... |&lt;br /&gt;
| **OKOK** | Row3, Row7... |&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 사용자가 `test`를 검색하면, 오라클은 5천만 건의 테이블을 다 읽는 대신 이 **역 인덱스 테이블에서 &#039;TEST&#039;라는 키 값을 찾아 해당 RowID만 콕 집어 가져옵니다.&lt;br /&gt;
----&lt;br /&gt;
==== &#039;부분 일치&#039;를 위한 역 인덱싱 심화 (Bigram / Trigram) ====&lt;br /&gt;
예를들어 데이터가  `=3=3=3=` 이나 `testtest`처럼 단어 경계가 모호한 경우, 일반적인 단어 단위 역 인덱싱으로는 한계가 있습니다. 이때는 **n-gram** 방식을 역 인덱스에 적용해야 합니다.&lt;br /&gt;
&lt;br /&gt;
* **기능:** 문자열을 n글자씩 쪼개서 인덱싱합니다.&lt;br /&gt;
* **설정 방법 (Oracle Text 기준):**&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
  -- 데이터를 글자 단위로 쪼개는 LEXER 설정&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_lexer&#039;, &#039;BASIC_LEXER&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_lexer&#039;, &#039;MIXED_CASE&#039;, &#039;YES&#039;); -- 대소문자 구분 여부&lt;br /&gt;
&lt;br /&gt;
  -- 핵심: 단어 중간 검색을 위한 인덱스 데이터 생성 설정&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_wordlist&#039;, &#039;BASIC_WORDLIST&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;SUBSTRING_INDEX&#039;, &#039;YES&#039;); &lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;PREFIX_INDEX&#039;, &#039;YES&#039;);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- 위 설정들을 적용하여 인덱스 생성&lt;br /&gt;
CREATE INDEX idx_tb_name_text ON tb_name(name)&lt;br /&gt;
INDEXTYPE IS CTXSYS.CONTEXT&lt;br /&gt;
PARAMETERS (&#039;LEXER my_lexer WORDLIST my_wordlist SYNC (ON COMMIT)&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 역 인덱싱 도입 시 성능 변화 (예상) ===&lt;br /&gt;
&lt;br /&gt;
* Full Scan (기존): 5천만 건 전체 블록 I/O 발생 → **수십 초~분 단위**&lt;br /&gt;
* Inverted Index (개선): 인덱스에서 키워드 탐색 후 해당 Row만 Fetch → **0.x초~수 초 이내**&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== 직접 구현하는 방식 (작동방식 원리 이해를 위해) ====&lt;br /&gt;
&lt;br /&gt;
* 만약 Oracle Text라는 기능을 쓰지 않고 SQL/테이블 구조로만 역 인덱싱을 흉내 내려면 다음과 같은 설계가 필요합니다 (권장하지는 않지만 이론적으로 가능합니다).&lt;br /&gt;
&lt;br /&gt;
# 맵핑 테이블 생성: `(word VARCHAR2(100), target_rowid ROWID)` 구조의 테이블 생성.&lt;br /&gt;
# 데이터 분해: `name` 컬럼의 데이터를 공백이나 특정 단위로 쪼개서 맵핑 테이블에 `INSERT`.&lt;br /&gt;
# 조회: 맵핑 테이블에서 `word = &#039;test&#039;`로 조회하여 원본 테이블과 `JOIN`.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; **현실적인 조언:** 5천만 건의 데이터를 직접 SQL로 쪼개서 관리하는 것은 동기화와 저장 공간 문제로 매우 어렵습니다. 오라클이 공식 지원하는 **Oracle Text**를 사용하시는 것이 가장 안정적인 역 인덱싱 구현 방법입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* 역 인덱싱(Oracle Text)을 적용하기 위해 **현재 운영 환경의 Tablespace 여유 공간**이나 **DML(입력/수정) 발생 빈도**를 체크해 보시는 것이 좋습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%97%AD_%EC%9D%B8%EB%8D%B1%EC%8B%B1(Inverted_Index)&amp;diff=1712</id>
		<title>역 인덱싱(Inverted Index)</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%97%AD_%EC%9D%B8%EB%8D%B1%EC%8B%B1(Inverted_Index)&amp;diff=1712"/>
		<updated>2026-03-13T02:13:11Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 역 인덱싱(Inverted Index)의 작동 원리 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 역 인덱싱 (Inverted Index)  ==&lt;br /&gt;
* Oracle Text(Context Index)가 바로 &#039;역 색인(Inverted Index)&#039; 원리를 이용한 기술임.&lt;br /&gt;
* 일반적인 B-Tree 인덱스가 책의 &#039;목차&#039;라면, 역 인덱스는 책 뒷부분의 **&#039;찾아보기(색인)&#039;**와 같습니다. &lt;br /&gt;
* 특정 단어가 어느 페이지(RowID)에 있는지 미리 지도로 그려두는 방식임.&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 역 인덱싱(Inverted Index)의 작동 원리 ===&lt;br /&gt;
*: 예를들어 5천만건의 대용량 테이블에 Context Index를 생성하면 내부적으로 다음과 같은 구조의 보조 테이블(주로 `$I` 테이블)이 생성됩니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;:&lt;br /&gt;
| 토큰(Token) | 문서 ID 리스트 (DocID / RowID) |&lt;br /&gt;
| --- | --- |&lt;br /&gt;
| **KIM** | Row1, Row5, Row10... |&lt;br /&gt;
| **TEST** | Row1, Row2, Row8, Row10... |&lt;br /&gt;
| **OKOK** | Row3, Row7... |&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 사용자가 `test`를 검색하면, 오라클은 5천만 건의 테이블을 다 읽는 대신 이 **역 인덱스 테이블에서 &#039;TEST&#039;라는 키 값을 찾아 해당 RowID만 콕 집어 가져옵니다.&lt;br /&gt;
----&lt;br /&gt;
==== &#039;부분 일치&#039;를 위한 역 인덱싱 심화 (Bigram / Trigram) ====&lt;br /&gt;
예를들어 데이터가  `=3=3=3=` 이나 `testtest`처럼 단어 경계가 모호한 경우, 일반적인 단어 단위 역 인덱싱으로는 한계가 있습니다. 이때는 **n-gram** 방식을 역 인덱스에 적용해야 합니다.&lt;br /&gt;
&lt;br /&gt;
* **기능:** 문자열을 n글자씩 쪼개서 인덱싱합니다.&lt;br /&gt;
* **설정 방법 (Oracle Text 기준):**&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
  -- 데이터를 글자 단위로 쪼개는 LEXER 설정&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_lexer&#039;, &#039;BASIC_LEXER&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_lexer&#039;, &#039;MIXED_CASE&#039;, &#039;YES&#039;); -- 대소문자 구분 여부&lt;br /&gt;
&lt;br /&gt;
  -- 핵심: 단어 중간 검색을 위한 인덱스 데이터 생성 설정&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_wordlist&#039;, &#039;BASIC_WORDLIST&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;SUBSTRING_INDEX&#039;, &#039;YES&#039;); &lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;PREFIX_INDEX&#039;, &#039;YES&#039;);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- 위 설정들을 적용하여 인덱스 생성&lt;br /&gt;
CREATE INDEX idx_tb_name_text ON tb_name(name)&lt;br /&gt;
INDEXTYPE IS CTXSYS.CONTEXT&lt;br /&gt;
PARAMETERS (&#039;LEXER my_lexer WORDLIST my_wordlist SYNC (ON COMMIT)&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 역 인덱싱 도입 시 성능 변화 (예상) ===&lt;br /&gt;
&lt;br /&gt;
* Full Scan (기존): 5천만 건 전체 블록 I/O 발생 → **수십 초~분 단위**&lt;br /&gt;
* Inverted Index (개선): 인덱스에서 키워드 탐색 후 해당 Row만 Fetch → **0.x초~수 초 이내**&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== 직접 구현하는 방식 (작동방식 원리 이해를 위해) ====&lt;br /&gt;
&lt;br /&gt;
* 만약 Oracle Text라는 기능을 쓰지 않고 SQL/테이블 구조로만 역 인덱싱을 흉내 내려면 다음과 같은 설계가 필요합니다 (권장하지는 않지만 이론적으로 가능합니다).&lt;br /&gt;
&lt;br /&gt;
# 맵핑 테이블 생성: `(word VARCHAR2(100), target_rowid ROWID)` 구조의 테이블 생성.&lt;br /&gt;
# 데이터 분해: `name` 컬럼의 데이터를 공백이나 특정 단위로 쪼개서 맵핑 테이블에 `INSERT`.&lt;br /&gt;
# 조회: 맵핑 테이블에서 `word = &#039;test&#039;`로 조회하여 원본 테이블과 `JOIN`.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; **현실적인 조언:** 5천만 건의 데이터를 직접 SQL로 쪼개서 관리하는 것은 동기화와 저장 공간 문제로 매우 어렵습니다. 오라클이 공식 지원하는 **Oracle Text**를 사용하시는 것이 가장 안정적인 역 인덱싱 구현 방법입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* 역 인덱싱(Oracle Text)을 적용하기 위해 **현재 운영 환경의 Tablespace 여유 공간**이나 **DML(입력/수정) 발생 빈도**를 체크해 보시는 것이 좋습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%97%AD_%EC%9D%B8%EB%8D%B1%EC%8B%B1(Inverted_Index)&amp;diff=1711</id>
		<title>역 인덱싱(Inverted Index)</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%97%AD_%EC%9D%B8%EB%8D%B1%EC%8B%B1(Inverted_Index)&amp;diff=1711"/>
		<updated>2026-03-13T02:12:55Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 역 인덱싱(Inverted Index)의 작동 원리 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 역 인덱싱 (Inverted Index)  ==&lt;br /&gt;
* Oracle Text(Context Index)가 바로 &#039;역 색인(Inverted Index)&#039; 원리를 이용한 기술임.&lt;br /&gt;
* 일반적인 B-Tree 인덱스가 책의 &#039;목차&#039;라면, 역 인덱스는 책 뒷부분의 **&#039;찾아보기(색인)&#039;**와 같습니다. &lt;br /&gt;
* 특정 단어가 어느 페이지(RowID)에 있는지 미리 지도로 그려두는 방식임.&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 역 인덱싱(Inverted Index)의 작동 원리 ===&lt;br /&gt;
* 예를들어 5천만건의 대용량 테이블에 Context Index를 생성하면 내부적으로 다음과 같은 구조의 보조 테이블(주로 `$I` 테이블)이 생성됩니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;:&lt;br /&gt;
| 토큰(Token) | 문서 ID 리스트 (DocID / RowID) |&lt;br /&gt;
| --- | --- |&lt;br /&gt;
| **KIM** | Row1, Row5, Row10... |&lt;br /&gt;
| **TEST** | Row1, Row2, Row8, Row10... |&lt;br /&gt;
| **OKOK** | Row3, Row7... |&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 사용자가 `test`를 검색하면, 오라클은 5천만 건의 테이블을 다 읽는 대신 이 **역 인덱스 테이블에서 &#039;TEST&#039;라는 키 값을 찾아 해당 RowID만 콕 집어 가져옵니다.&lt;br /&gt;
----&lt;br /&gt;
==== &#039;부분 일치&#039;를 위한 역 인덱싱 심화 (Bigram / Trigram) ====&lt;br /&gt;
예를들어 데이터가  `=3=3=3=` 이나 `testtest`처럼 단어 경계가 모호한 경우, 일반적인 단어 단위 역 인덱싱으로는 한계가 있습니다. 이때는 **n-gram** 방식을 역 인덱스에 적용해야 합니다.&lt;br /&gt;
&lt;br /&gt;
* **기능:** 문자열을 n글자씩 쪼개서 인덱싱합니다.&lt;br /&gt;
* **설정 방법 (Oracle Text 기준):**&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
  -- 데이터를 글자 단위로 쪼개는 LEXER 설정&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_lexer&#039;, &#039;BASIC_LEXER&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_lexer&#039;, &#039;MIXED_CASE&#039;, &#039;YES&#039;); -- 대소문자 구분 여부&lt;br /&gt;
&lt;br /&gt;
  -- 핵심: 단어 중간 검색을 위한 인덱스 데이터 생성 설정&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_wordlist&#039;, &#039;BASIC_WORDLIST&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;SUBSTRING_INDEX&#039;, &#039;YES&#039;); &lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;PREFIX_INDEX&#039;, &#039;YES&#039;);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- 위 설정들을 적용하여 인덱스 생성&lt;br /&gt;
CREATE INDEX idx_tb_name_text ON tb_name(name)&lt;br /&gt;
INDEXTYPE IS CTXSYS.CONTEXT&lt;br /&gt;
PARAMETERS (&#039;LEXER my_lexer WORDLIST my_wordlist SYNC (ON COMMIT)&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 역 인덱싱 도입 시 성능 변화 (예상) ===&lt;br /&gt;
&lt;br /&gt;
* Full Scan (기존): 5천만 건 전체 블록 I/O 발생 → **수십 초~분 단위**&lt;br /&gt;
* Inverted Index (개선): 인덱스에서 키워드 탐색 후 해당 Row만 Fetch → **0.x초~수 초 이내**&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== 직접 구현하는 방식 (작동방식 원리 이해를 위해) ====&lt;br /&gt;
&lt;br /&gt;
* 만약 Oracle Text라는 기능을 쓰지 않고 SQL/테이블 구조로만 역 인덱싱을 흉내 내려면 다음과 같은 설계가 필요합니다 (권장하지는 않지만 이론적으로 가능합니다).&lt;br /&gt;
&lt;br /&gt;
# 맵핑 테이블 생성: `(word VARCHAR2(100), target_rowid ROWID)` 구조의 테이블 생성.&lt;br /&gt;
# 데이터 분해: `name` 컬럼의 데이터를 공백이나 특정 단위로 쪼개서 맵핑 테이블에 `INSERT`.&lt;br /&gt;
# 조회: 맵핑 테이블에서 `word = &#039;test&#039;`로 조회하여 원본 테이블과 `JOIN`.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; **현실적인 조언:** 5천만 건의 데이터를 직접 SQL로 쪼개서 관리하는 것은 동기화와 저장 공간 문제로 매우 어렵습니다. 오라클이 공식 지원하는 **Oracle Text**를 사용하시는 것이 가장 안정적인 역 인덱싱 구현 방법입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* 역 인덱싱(Oracle Text)을 적용하기 위해 **현재 운영 환경의 Tablespace 여유 공간**이나 **DML(입력/수정) 발생 빈도**를 체크해 보시는 것이 좋습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%97%AD_%EC%9D%B8%EB%8D%B1%EC%8B%B1(Inverted_Index)&amp;diff=1710</id>
		<title>역 인덱싱(Inverted Index)</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%97%AD_%EC%9D%B8%EB%8D%B1%EC%8B%B1(Inverted_Index)&amp;diff=1710"/>
		<updated>2026-03-13T02:12:43Z</updated>

		<summary type="html">&lt;p&gt;Oracle: 새 문서: == 역 인덱싱 (Inverted Index)  == * Oracle Text(Context Index)가 바로 &amp;#039;역 색인(Inverted Index)&amp;#039; 원리를 이용한 기술임. * 일반적인 B-Tree 인덱스가 책의 &amp;#039;목차&amp;#039;라면, 역 인덱스는 책 뒷부분의 **&amp;#039;찾아보기(색인)&amp;#039;**와 같습니다.  * 특정 단어가 어느 페이지(RowID)에 있는지 미리 지도로 그려두는 방식임. ----  === 역 인덱싱(Inverted Index)의 작동 원리 === * 예를들어 5천만건의 대용량 테이블에...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 역 인덱싱 (Inverted Index)  ==&lt;br /&gt;
* Oracle Text(Context Index)가 바로 &#039;역 색인(Inverted Index)&#039; 원리를 이용한 기술임.&lt;br /&gt;
* 일반적인 B-Tree 인덱스가 책의 &#039;목차&#039;라면, 역 인덱스는 책 뒷부분의 **&#039;찾아보기(색인)&#039;**와 같습니다. &lt;br /&gt;
* 특정 단어가 어느 페이지(RowID)에 있는지 미리 지도로 그려두는 방식임.&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 역 인덱싱(Inverted Index)의 작동 원리 ===&lt;br /&gt;
* 예를들어 5천만건의 대용량 테이블에 Context Index를 생성하면 내부적으로 다음과 같은 구조의 보조 테이블(주로 `$I` 테이블)이 생성됩니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
| 토큰(Token) | 문서 ID 리스트 (DocID / RowID) |&lt;br /&gt;
| --- | --- |&lt;br /&gt;
| **KIM** | Row1, Row5, Row10... |&lt;br /&gt;
| **TEST** | Row1, Row2, Row8, Row10... |&lt;br /&gt;
| **OKOK** | Row3, Row7... |&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
* 사용자가 `test`를 검색하면, 오라클은 5천만 건의 테이블을 다 읽는 대신 이 **역 인덱스 테이블에서 &#039;TEST&#039;라는 키 값을 찾아 해당 RowID만 콕 집어 가져옵니다.&lt;br /&gt;
----&lt;br /&gt;
==== &#039;부분 일치&#039;를 위한 역 인덱싱 심화 (Bigram / Trigram) ====&lt;br /&gt;
예를들어 데이터가  `=3=3=3=` 이나 `testtest`처럼 단어 경계가 모호한 경우, 일반적인 단어 단위 역 인덱싱으로는 한계가 있습니다. 이때는 **n-gram** 방식을 역 인덱스에 적용해야 합니다.&lt;br /&gt;
&lt;br /&gt;
* **기능:** 문자열을 n글자씩 쪼개서 인덱싱합니다.&lt;br /&gt;
* **설정 방법 (Oracle Text 기준):**&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
BEGIN&lt;br /&gt;
  -- 데이터를 글자 단위로 쪼개는 LEXER 설정&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_lexer&#039;, &#039;BASIC_LEXER&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_lexer&#039;, &#039;MIXED_CASE&#039;, &#039;YES&#039;); -- 대소문자 구분 여부&lt;br /&gt;
&lt;br /&gt;
  -- 핵심: 단어 중간 검색을 위한 인덱스 데이터 생성 설정&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_wordlist&#039;, &#039;BASIC_WORDLIST&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;SUBSTRING_INDEX&#039;, &#039;YES&#039;); &lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;PREFIX_INDEX&#039;, &#039;YES&#039;);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- 위 설정들을 적용하여 인덱스 생성&lt;br /&gt;
CREATE INDEX idx_tb_name_text ON tb_name(name)&lt;br /&gt;
INDEXTYPE IS CTXSYS.CONTEXT&lt;br /&gt;
PARAMETERS (&#039;LEXER my_lexer WORDLIST my_wordlist SYNC (ON COMMIT)&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== 역 인덱싱 도입 시 성능 변화 (예상) ===&lt;br /&gt;
&lt;br /&gt;
* Full Scan (기존): 5천만 건 전체 블록 I/O 발생 → **수십 초~분 단위**&lt;br /&gt;
* Inverted Index (개선): 인덱스에서 키워드 탐색 후 해당 Row만 Fetch → **0.x초~수 초 이내**&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
==== 직접 구현하는 방식 (작동방식 원리 이해를 위해) ====&lt;br /&gt;
&lt;br /&gt;
* 만약 Oracle Text라는 기능을 쓰지 않고 SQL/테이블 구조로만 역 인덱싱을 흉내 내려면 다음과 같은 설계가 필요합니다 (권장하지는 않지만 이론적으로 가능합니다).&lt;br /&gt;
&lt;br /&gt;
# 맵핑 테이블 생성: `(word VARCHAR2(100), target_rowid ROWID)` 구조의 테이블 생성.&lt;br /&gt;
# 데이터 분해: `name` 컬럼의 데이터를 공백이나 특정 단위로 쪼개서 맵핑 테이블에 `INSERT`.&lt;br /&gt;
# 조회: 맵핑 테이블에서 `word = &#039;test&#039;`로 조회하여 원본 테이블과 `JOIN`.&lt;br /&gt;
&lt;br /&gt;
&amp;gt; **현실적인 조언:** 5천만 건의 데이터를 직접 SQL로 쪼개서 관리하는 것은 동기화와 저장 공간 문제로 매우 어렵습니다. 오라클이 공식 지원하는 **Oracle Text**를 사용하시는 것이 가장 안정적인 역 인덱싱 구현 방법입니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* 역 인덱싱(Oracle Text)을 적용하기 위해 **현재 운영 환경의 Tablespace 여유 공간**이나 **DML(입력/수정) 발생 빈도**를 체크해 보시는 것이 좋습니다.&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%9D%B8%EB%8D%B1%EC%8A%A4_%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98&amp;diff=1709</id>
		<title>인덱스 아키텍처</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%9D%B8%EB%8D%B1%EC%8A%A4_%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98&amp;diff=1709"/>
		<updated>2026-03-13T02:04:26Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 인덱스 아키텍처 ==&lt;br /&gt;
=== [[B*Tree 인덱스]] ===&lt;br /&gt;
=== [[역 인덱싱(Inverted Index)]] ===&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%9D%B8%EB%8D%B1%EC%8A%A4_%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98&amp;diff=1708</id>
		<title>인덱스 아키텍처</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%9D%B8%EB%8D%B1%EC%8A%A4_%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98&amp;diff=1708"/>
		<updated>2026-03-13T02:04:18Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 인덱스 아키텍처 ==&lt;br /&gt;
=== [[B*Tree 인덱스]] ===&lt;br /&gt;
=== [[역 인덱싱(Inverted Index)]]&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%95%9E%25_LIKE_%ED%8A%9C%EB%8B%9D&amp;diff=1707</id>
		<title>앞% LIKE 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%95%9E%25_LIKE_%ED%8A%9C%EB%8B%9D&amp;diff=1707"/>
		<updated>2026-03-13T02:02:21Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 앞% LIKE 튜닝 방안 == &lt;br /&gt;
&lt;br /&gt;
{{요점&lt;br /&gt;
|내용=&lt;br /&gt;
# Oracle Text &lt;br /&gt;
#: :매우 높음보통대량의 텍스트 검색에 최적화된 표준 방식&lt;br /&gt;
# Parallel Query&lt;br /&gt;
#: :높음낮음인덱스 없이 하드웨어 자원으로 해결&lt;br /&gt;
# B-Tree Index는 LIKE &#039;%~&#039; 사용시 인덱스 사용할수 없음.&lt;br /&gt;
#: :LIKE &#039;%...&#039; 형태에서는 사실상 무용지물&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* 성능 저하 테이블 정보&lt;br /&gt;
** (대용량) 5천만 건의 데이터와 하루 1만 건의 입력,수정 발생 &lt;br /&gt;
&lt;br /&gt;
# Context Index 도입이 성능 문제를 해결할 가장 현실적이고 강력한 방법&lt;br /&gt;
# 단순히 인덱스를 생성하는 것을 넘어, **실제 운영 환경에서 성능과 데이터 정합성을 모두 잡기 위해 반드시 설정해야 할 사항 정리&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
=== 데이터 클린징 ===&lt;br /&gt;
=== 정규표현식을 사용한 Function Based Index 생성 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Oracle Text 인덱스 생성 및 최적화 전략 ===&lt;br /&gt;
* 일반 B-Tree 인덱스와 달리 Context 인덱스는 생성 시 몇 가지 파라미터를 지정하는 것이 중요합니다.&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 1. 인덱스 생성 (대용량 테이블은  병렬 처리 권장)&lt;br /&gt;
-- SYNC (ON COMMIT): 데이터가 INSERT/UPDATE 될 때 인덱스에 즉시 반영&lt;br /&gt;
CREATE INDEX idx_tb_name_text ON tb_name(name) &lt;br /&gt;
INDEXTYPE IS CTXSYS.CONTEXT &lt;br /&gt;
PARAMETERS (&#039;SYNC (ON COMMIT) MEMORY 500M&#039;); &lt;br /&gt;
&lt;br /&gt;
-- 2. 쿼리 실행 (반드시 CONTAINS 함수 사용)&lt;br /&gt;
SELECT name &lt;br /&gt;
FROM tb_name &lt;br /&gt;
WHERE CONTAINS(name, &#039;test&#039;) &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* **MEMORY 500M:** 인덱스 생성 시 사용할 메모리 크기입니다. 5천만 건이라면 기본값보다 크게 잡아야 생성 속도가 빠릅니다.&lt;br /&gt;
* **SYNC (ON COMMIT):** 데이터 변경이 잦다면 이 옵션을 넣어야 조회가 실시간으로 반영됩니다. 만약 쓰기 작업이 너무 많아 성능 저하가 우려된다면 `SYNC (EVERY &amp;quot;FREQ=MINUTELY;INTERVAL=5&amp;quot;)` 처럼 주기적 동기화 방식을 쓸 수도 있습니다.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
### 2. 검색 패턴별 쿼리 작성법&lt;br /&gt;
&lt;br /&gt;
`LIKE`와 `CONTAINS`는 문법이 조금 다릅니다. 사용자의 검색 요구사항에 맞춰 아래와 같이 대응하세요.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 검색 패턴별 쿼리 작성법&lt;br /&gt;
|-&lt;br /&gt;
! 검색 요구사항 !! 기존 LIKE (Full Scan) !! !!Oracle Text (Index Scan)&lt;br /&gt;
|-&lt;br /&gt;
| **단어 포함** || `LIKE &#039;%test%&#039;` || `CONTAINS(name, &#039;test&#039;) &amp;gt; 0` &lt;br /&gt;
|-&lt;br /&gt;
| **여러 단어 포함 (AND)** || `LIKE &#039;%test%&#039; AND LIKE &#039;%kim%&#039;` || `CONTAINS(name, &#039;test AND kim&#039;) &amp;gt; 0` &lt;br /&gt;
|-&lt;br /&gt;
| **여러 단어 중 하나 (OR)** || `LIKE &#039;%test%&#039; OR LIKE &#039;%kim%&#039;` || `CONTAINS(name, &#039;test OR kim&#039;) &amp;gt; 0` &lt;br /&gt;
|-&lt;br /&gt;
| **특수문자 포함** || `LIKE &#039;%=3=3=3=%&#039;` || `CONTAINS(name, &#039;\{=3=3=3=\}&#039;) &amp;gt; 0` &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
**주의:** Oracle Text에서 특정 특수문자는 예약어이므로 중괄호(`{ }`)로 감싸야 정확히 검색됩니다.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
### 3. 운영 시 고려해야 할 리스크 관리&lt;br /&gt;
&lt;br /&gt;
5천만 건 규모에서 Context 인덱스를 운영할 때 놓치지 말아야 할 포인트입니다.&lt;br /&gt;
&lt;br /&gt;
1. **인덱스 단편화 (Fragmentation):**&lt;br /&gt;
데이터 변경(DML)이 잦으면 인덱스가 조각납니다. 성능 유지를 위해 주기적으로 최적화가 필요합니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
EXEC CTX_DDL.OPTIMIZE_INDEX(&#039;idx_tb_name_text&#039;, &#039;FULL&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. **저장 공간 (Storage):**&lt;br /&gt;
이 인덱스는 내부적으로 `$I`, `$R` 등의 보조 테이블을 생성합니다. 원본 데이터 크기의 약 10~20% 정도 추가 저장 공간을 확보해 두세요.&lt;br /&gt;
3. **검색어 길이:**&lt;br /&gt;
너무 짧은 단어(예: 한 글자) 검색이 잦다면 인덱스 설정 시 `BASIC_LEXER`에서 별도의 처리가 필요할 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
### 4. 만약 &#039;부분 일치&#039;가 더 까다롭다면?&lt;br /&gt;
&lt;br /&gt;
만약 `test`가 아니라 `est`처럼 단어의 중간 일부만 검색해야 하는 상황이 많다면, 인덱스 생성 시 **`SUBSTRING_INDEX`** 옵션을 활성화해야 합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Wordlist 설정 (중간 문자열 검색 최적화)&lt;br /&gt;
BEGIN&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_wordlist&#039;, &#039;BASIC_WORDLIST&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;SUBSTRING_INDEX&#039;, &#039;YES&#039;);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- 인덱스 생성 시 적용&lt;br /&gt;
CREATE INDEX idx_tb_name_text ON tb_name(name) &lt;br /&gt;
INDEXTYPE IS CTXSYS.CONTEXT &lt;br /&gt;
PARAMETERS (&#039;WORDLIST my_wordlist SYNC (ON COMMIT)&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
이 방법은 현재 상황에서 **Full Table Scan 비용을 획기적으로 줄일 수 있는 마법 같은 해결책**이 될 것입니다.&lt;br /&gt;
&lt;br /&gt;
*  인덱스를 생성하기 전에, 현재 해당 컬럼(`name`)의 데이터 중 가장 긴 문자열의 길이나 평균적인 데이터 형태를 알면 &lt;br /&gt;
 그에 맞춰 `LEXER` 설정을 더 정교하게 다듬을수 있음&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%95%9E%25_LIKE_%ED%8A%9C%EB%8B%9D&amp;diff=1706</id>
		<title>앞% LIKE 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%95%9E%25_LIKE_%ED%8A%9C%EB%8B%9D&amp;diff=1706"/>
		<updated>2026-03-13T02:01:32Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 앞% LIKE 튜닝 방안 == &lt;br /&gt;
&lt;br /&gt;
{{요점&lt;br /&gt;
|내용=&lt;br /&gt;
&lt;br /&gt;
# Oracle Text (CTXSYS.CONTEXT)&lt;br /&gt;
#: :매우 높음보통대량의 텍스트 검색에 최적화된 표준 방식&lt;br /&gt;
# Parallel Query&lt;br /&gt;
#: :높음낮음인덱스 없이 하드웨어 자원으로 해결&lt;br /&gt;
# B-Tree Index는 LIKE &#039;%~&#039; 사용시 인덱스 사용할수 없음.&lt;br /&gt;
#: :LIKE &#039;%...&#039; 형태에서는 사실상 무용지물&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* 성능 저하 테이블 정보&lt;br /&gt;
** (대용량) 5천만 건의 데이터와 하루 1만 건의 입력,수정 발생 &lt;br /&gt;
&lt;br /&gt;
# Context Index 도입이 성능 문제를 해결할 가장 현실적이고 강력한 방법&lt;br /&gt;
# 단순히 인덱스를 생성하는 것을 넘어, **실제 운영 환경에서 성능과 데이터 정합성을 모두 잡기 위해 반드시 설정해야 할 사항 정리&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== 데이터 클린징 ===&lt;br /&gt;
=== 정규표현식을 사용한 Function Based Index 생성 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Oracle Text 인덱스 생성 및 최적화 전략 ===&lt;br /&gt;
* 일반 B-Tree 인덱스와 달리 Context 인덱스는 생성 시 몇 가지 파라미터를 지정하는 것이 중요합니다.&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 1. 인덱스 생성 (대용량 테이블은  병렬 처리 권장)&lt;br /&gt;
-- SYNC (ON COMMIT): 데이터가 INSERT/UPDATE 될 때 인덱스에 즉시 반영&lt;br /&gt;
CREATE INDEX idx_tb_name_text ON tb_name(name) &lt;br /&gt;
INDEXTYPE IS CTXSYS.CONTEXT &lt;br /&gt;
PARAMETERS (&#039;SYNC (ON COMMIT) MEMORY 500M&#039;); &lt;br /&gt;
&lt;br /&gt;
-- 2. 쿼리 실행 (반드시 CONTAINS 함수 사용)&lt;br /&gt;
SELECT name &lt;br /&gt;
FROM tb_name &lt;br /&gt;
WHERE CONTAINS(name, &#039;test&#039;) &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* **MEMORY 500M:** 인덱스 생성 시 사용할 메모리 크기입니다. 5천만 건이라면 기본값보다 크게 잡아야 생성 속도가 빠릅니다.&lt;br /&gt;
* **SYNC (ON COMMIT):** 데이터 변경이 잦다면 이 옵션을 넣어야 조회가 실시간으로 반영됩니다. 만약 쓰기 작업이 너무 많아 성능 저하가 우려된다면 `SYNC (EVERY &amp;quot;FREQ=MINUTELY;INTERVAL=5&amp;quot;)` 처럼 주기적 동기화 방식을 쓸 수도 있습니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
### 2. 검색 패턴별 쿼리 작성법&lt;br /&gt;
&lt;br /&gt;
`LIKE`와 `CONTAINS`는 문법이 조금 다릅니다. 사용자의 검색 요구사항에 맞춰 아래와 같이 대응하세요.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 검색 패턴별 쿼리 작성법&lt;br /&gt;
|-&lt;br /&gt;
! 검색 요구사항 !! 기존 LIKE (Full Scan) !! !!Oracle Text (Index Scan)&lt;br /&gt;
|-&lt;br /&gt;
| **단어 포함** || `LIKE &#039;%test%&#039;` || `CONTAINS(name, &#039;test&#039;) &amp;gt; 0` &lt;br /&gt;
|-&lt;br /&gt;
| **여러 단어 포함 (AND)** || `LIKE &#039;%test%&#039; AND LIKE &#039;%kim%&#039;` || `CONTAINS(name, &#039;test AND kim&#039;) &amp;gt; 0` &lt;br /&gt;
|-&lt;br /&gt;
| **여러 단어 중 하나 (OR)** || `LIKE &#039;%test%&#039; OR LIKE &#039;%kim%&#039;` || `CONTAINS(name, &#039;test OR kim&#039;) &amp;gt; 0` &lt;br /&gt;
|-&lt;br /&gt;
| **특수문자 포함** || `LIKE &#039;%=3=3=3=%&#039;` || `CONTAINS(name, &#039;\{=3=3=3=\}&#039;) &amp;gt; 0` &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
**주의:** Oracle Text에서 특정 특수문자는 예약어이므로 중괄호(`{ }`)로 감싸야 정확히 검색됩니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
### 3. 운영 시 고려해야 할 리스크 관리&lt;br /&gt;
&lt;br /&gt;
5천만 건 규모에서 Context 인덱스를 운영할 때 놓치지 말아야 할 포인트입니다.&lt;br /&gt;
&lt;br /&gt;
1. **인덱스 단편화 (Fragmentation):**&lt;br /&gt;
데이터 변경(DML)이 잦으면 인덱스가 조각납니다. 성능 유지를 위해 주기적으로 최적화가 필요합니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
EXEC CTX_DDL.OPTIMIZE_INDEX(&#039;idx_tb_name_text&#039;, &#039;FULL&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. **저장 공간 (Storage):**&lt;br /&gt;
이 인덱스는 내부적으로 `$I`, `$R` 등의 보조 테이블을 생성합니다. 원본 데이터 크기의 약 10~20% 정도 추가 저장 공간을 확보해 두세요.&lt;br /&gt;
3. **검색어 길이:**&lt;br /&gt;
너무 짧은 단어(예: 한 글자) 검색이 잦다면 인덱스 설정 시 `BASIC_LEXER`에서 별도의 처리가 필요할 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
### 4. 만약 &#039;부분 일치&#039;가 더 까다롭다면?&lt;br /&gt;
&lt;br /&gt;
만약 `test`가 아니라 `est`처럼 단어의 중간 일부만 검색해야 하는 상황이 많다면, 인덱스 생성 시 **`SUBSTRING_INDEX`** 옵션을 활성화해야 합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Wordlist 설정 (중간 문자열 검색 최적화)&lt;br /&gt;
BEGIN&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_wordlist&#039;, &#039;BASIC_WORDLIST&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;SUBSTRING_INDEX&#039;, &#039;YES&#039;);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- 인덱스 생성 시 적용&lt;br /&gt;
CREATE INDEX idx_tb_name_text ON tb_name(name) &lt;br /&gt;
INDEXTYPE IS CTXSYS.CONTEXT &lt;br /&gt;
PARAMETERS (&#039;WORDLIST my_wordlist SYNC (ON COMMIT)&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
이 방법은 현재 상황에서 **Full Table Scan 비용을 획기적으로 줄일 수 있는 마법 같은 해결책**이 될 것입니다.&lt;br /&gt;
&lt;br /&gt;
*  인덱스를 생성하기 전에, 현재 해당 컬럼(`name`)의 데이터 중 가장 긴 문자열의 길이나 평균적인 데이터 형태를 알면 &lt;br /&gt;
 그에 맞춰 `LEXER` 설정을 더 정교하게 다듬을수 있음&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%95%9E%25_LIKE_%ED%8A%9C%EB%8B%9D&amp;diff=1705</id>
		<title>앞% LIKE 튜닝</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%95%9E%25_LIKE_%ED%8A%9C%EB%8B%9D&amp;diff=1705"/>
		<updated>2026-03-13T02:01:08Z</updated>

		<summary type="html">&lt;p&gt;Oracle: 새 문서:  == 앞% LIKE 튜닝 방안 ==   {{요점 |내용= 앞% LIKE 튜닝 방안 # B-Tree Index는 LIKE &amp;#039;%~&amp;#039; 사용시 인덱스 사용할수 없음. #: :LIKE &amp;#039;%...&amp;#039; 형태에서는 사실상 무용지물 # REGEXP_SUBSTR + FUNCTION BASED INDEX를 이용한 인덱싱 처리  # Oracle Text (CTXSYS.CONTEXT) 이용  #: :매우 높음보통대량의 텍스트 검색에 최적화된 표준 방식 # Parallel Query #: :높음낮음인덱스 없이 하드웨어 자원으로 해결  }}  * 성...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== 앞% LIKE 튜닝 방안 == &lt;br /&gt;
&lt;br /&gt;
{{요점&lt;br /&gt;
|내용= 앞% LIKE 튜닝 방안&lt;br /&gt;
# B-Tree Index는 LIKE &#039;%~&#039; 사용시 인덱스 사용할수 없음.&lt;br /&gt;
#: :LIKE &#039;%...&#039; 형태에서는 사실상 무용지물&lt;br /&gt;
# REGEXP_SUBSTR + FUNCTION BASED INDEX를 이용한 인덱싱 처리 &lt;br /&gt;
# Oracle Text (CTXSYS.CONTEXT) 이용 &lt;br /&gt;
#: :매우 높음보통대량의 텍스트 검색에 최적화된 표준 방식&lt;br /&gt;
# Parallel Query&lt;br /&gt;
#: :높음낮음인덱스 없이 하드웨어 자원으로 해결&lt;br /&gt;
&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* 성능 저하 테이블 정보&lt;br /&gt;
** (대용량) 5천만 건의 데이터와 하루 1만 건의 입력,수정 발생 &lt;br /&gt;
&lt;br /&gt;
# Context Index 도입이 성능 문제를 해결할 가장 현실적이고 강력한 방법&lt;br /&gt;
# 단순히 인덱스를 생성하는 것을 넘어, **실제 운영 환경에서 성능과 데이터 정합성을 모두 잡기 위해 반드시 설정해야 할 사항 정리&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== 데이터 클린징 ===&lt;br /&gt;
=== 정규표현식을 사용한 Function Based Index 생성 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Oracle Text 인덱스 생성 및 최적화 전략 ===&lt;br /&gt;
* 일반 B-Tree 인덱스와 달리 Context 인덱스는 생성 시 몇 가지 파라미터를 지정하는 것이 중요합니다.&lt;br /&gt;
*:&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 1. 인덱스 생성 (대용량 테이블은  병렬 처리 권장)&lt;br /&gt;
-- SYNC (ON COMMIT): 데이터가 INSERT/UPDATE 될 때 인덱스에 즉시 반영&lt;br /&gt;
CREATE INDEX idx_tb_name_text ON tb_name(name) &lt;br /&gt;
INDEXTYPE IS CTXSYS.CONTEXT &lt;br /&gt;
PARAMETERS (&#039;SYNC (ON COMMIT) MEMORY 500M&#039;); &lt;br /&gt;
&lt;br /&gt;
-- 2. 쿼리 실행 (반드시 CONTAINS 함수 사용)&lt;br /&gt;
SELECT name &lt;br /&gt;
FROM tb_name &lt;br /&gt;
WHERE CONTAINS(name, &#039;test&#039;) &amp;gt; 0;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* **MEMORY 500M:** 인덱스 생성 시 사용할 메모리 크기입니다. 5천만 건이라면 기본값보다 크게 잡아야 생성 속도가 빠릅니다.&lt;br /&gt;
* **SYNC (ON COMMIT):** 데이터 변경이 잦다면 이 옵션을 넣어야 조회가 실시간으로 반영됩니다. 만약 쓰기 작업이 너무 많아 성능 저하가 우려된다면 `SYNC (EVERY &amp;quot;FREQ=MINUTELY;INTERVAL=5&amp;quot;)` 처럼 주기적 동기화 방식을 쓸 수도 있습니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
### 2. 검색 패턴별 쿼리 작성법&lt;br /&gt;
&lt;br /&gt;
`LIKE`와 `CONTAINS`는 문법이 조금 다릅니다. 사용자의 검색 요구사항에 맞춰 아래와 같이 대응하세요.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ 검색 패턴별 쿼리 작성법&lt;br /&gt;
|-&lt;br /&gt;
! 검색 요구사항 !! 기존 LIKE (Full Scan) !! !!Oracle Text (Index Scan)&lt;br /&gt;
|-&lt;br /&gt;
| **단어 포함** || `LIKE &#039;%test%&#039;` || `CONTAINS(name, &#039;test&#039;) &amp;gt; 0` &lt;br /&gt;
|-&lt;br /&gt;
| **여러 단어 포함 (AND)** || `LIKE &#039;%test%&#039; AND LIKE &#039;%kim%&#039;` || `CONTAINS(name, &#039;test AND kim&#039;) &amp;gt; 0` &lt;br /&gt;
|-&lt;br /&gt;
| **여러 단어 중 하나 (OR)** || `LIKE &#039;%test%&#039; OR LIKE &#039;%kim%&#039;` || `CONTAINS(name, &#039;test OR kim&#039;) &amp;gt; 0` &lt;br /&gt;
|-&lt;br /&gt;
| **특수문자 포함** || `LIKE &#039;%=3=3=3=%&#039;` || `CONTAINS(name, &#039;\{=3=3=3=\}&#039;) &amp;gt; 0` &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
**주의:** Oracle Text에서 특정 특수문자는 예약어이므로 중괄호(`{ }`)로 감싸야 정확히 검색됩니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
### 3. 운영 시 고려해야 할 리스크 관리&lt;br /&gt;
&lt;br /&gt;
5천만 건 규모에서 Context 인덱스를 운영할 때 놓치지 말아야 할 포인트입니다.&lt;br /&gt;
&lt;br /&gt;
1. **인덱스 단편화 (Fragmentation):**&lt;br /&gt;
데이터 변경(DML)이 잦으면 인덱스가 조각납니다. 성능 유지를 위해 주기적으로 최적화가 필요합니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
EXEC CTX_DDL.OPTIMIZE_INDEX(&#039;idx_tb_name_text&#039;, &#039;FULL&#039;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. **저장 공간 (Storage):**&lt;br /&gt;
이 인덱스는 내부적으로 `$I`, `$R` 등의 보조 테이블을 생성합니다. 원본 데이터 크기의 약 10~20% 정도 추가 저장 공간을 확보해 두세요.&lt;br /&gt;
3. **검색어 길이:**&lt;br /&gt;
너무 짧은 단어(예: 한 글자) 검색이 잦다면 인덱스 설정 시 `BASIC_LEXER`에서 별도의 처리가 필요할 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
### 4. 만약 &#039;부분 일치&#039;가 더 까다롭다면?&lt;br /&gt;
&lt;br /&gt;
만약 `test`가 아니라 `est`처럼 단어의 중간 일부만 검색해야 하는 상황이 많다면, 인덱스 생성 시 **`SUBSTRING_INDEX`** 옵션을 활성화해야 합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Wordlist 설정 (중간 문자열 검색 최적화)&lt;br /&gt;
BEGIN&lt;br /&gt;
  CTX_DDL.CREATE_PREFERENCE(&#039;my_wordlist&#039;, &#039;BASIC_WORDLIST&#039;);&lt;br /&gt;
  CTX_DDL.SET_ATTRIBUTE(&#039;my_wordlist&#039;, &#039;SUBSTRING_INDEX&#039;, &#039;YES&#039;);&lt;br /&gt;
END;&lt;br /&gt;
/&lt;br /&gt;
&lt;br /&gt;
-- 인덱스 생성 시 적용&lt;br /&gt;
CREATE INDEX idx_tb_name_text ON tb_name(name) &lt;br /&gt;
INDEXTYPE IS CTXSYS.CONTEXT &lt;br /&gt;
PARAMETERS (&#039;WORDLIST my_wordlist SYNC (ON COMMIT)&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
이 방법은 현재 상황에서 **Full Table Scan 비용을 획기적으로 줄일 수 있는 마법 같은 해결책**이 될 것입니다.&lt;br /&gt;
&lt;br /&gt;
*  인덱스를 생성하기 전에, 현재 해당 컬럼(`name`)의 데이터 중 가장 긴 문자열의 길이나 평균적인 데이터 형태를 알면 &lt;br /&gt;
 그에 맞춰 `LEXER` 설정을 더 정교하게 다듬을수 있음&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1704</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1704"/>
		<updated>2026-01-26T02:34:45Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::- NO_MERGE 힌트는 인라인뷰 나 WITH절 쿼리를 메인쿼리와 합치지 말고 별개로 수행하라는 힌트임.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
::* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
::* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
::* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
::*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
::* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 병렬 처리 최적화 ===&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{요점&lt;br /&gt;
|배경색 = #f7d4063e&lt;br /&gt;
|선굵기 = 3px&lt;br /&gt;
|테두리색 = #de5a5a&lt;br /&gt;
|사이즈 = 100%&lt;br /&gt;
|둥굴기 = 4px&lt;br /&gt;
|스타일 = dashed &lt;br /&gt;
|내용 =&#039;&#039;&#039;* 실행 계획 확인 방법&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&#039;&#039;&#039;(중요) 실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&#039;&#039;&#039;&amp;lt;/center&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]]&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1703</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1703"/>
		<updated>2026-01-26T02:33:49Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::- NO_MERGE 힌트는 인라인뷰 나 WITH절 쿼리를 메인쿼리와 합치지 말고 별개로 수행하라는 힌트임.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
::* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
::* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
::* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
::*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
::* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 병렬 처리 최적화 ===&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{요점&lt;br /&gt;
|배경색 = #f7d4063e&lt;br /&gt;
|선굵기 = 3px&lt;br /&gt;
|테두리색 = #de5a5a&lt;br /&gt;
|사이즈 = 100%&lt;br /&gt;
|둥굴기 = 4px&lt;br /&gt;
|스타일 = dashed&lt;br /&gt;
|제목 = * 실행 계획 확인 방법&lt;br /&gt;
|내용 =&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&#039;&#039;&#039;(중요) 실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&#039;&#039;&#039;&amp;lt;/center&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]]&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1702</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1702"/>
		<updated>2026-01-26T02:21:06Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 병렬 처리 최적화 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::- NO_MERGE 힌트는 인라인뷰 나 WITH절 쿼리를 메인쿼리와 합치지 말고 별개로 수행하라는 힌트임.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
::* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
::* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
::* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
::*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
::* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 병렬 처리 최적화 ===&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::&#039;&#039;&#039;(중요) 실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]]&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1701</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1701"/>
		<updated>2026-01-26T02:20:44Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 병렬 처리 최적화 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::- NO_MERGE 힌트는 인라인뷰 나 WITH절 쿼리를 메인쿼리와 합치지 말고 별개로 수행하라는 힌트임.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
::* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
::* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
::* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
::*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
::* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 병렬 처리 최적화 ===&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::::&#039;&#039;&#039;(중요) 실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]]&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1700</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1700"/>
		<updated>2026-01-26T02:20:15Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::- NO_MERGE 힌트는 인라인뷰 나 WITH절 쿼리를 메인쿼리와 합치지 말고 별개로 수행하라는 힌트임.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
::* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
::* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
::* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
::*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
::* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 병렬 처리 최적화 ===&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;(중요) 실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]]&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1699</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1699"/>
		<updated>2026-01-26T02:19:23Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 중복 작업 방지 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::- NO_MERGE 힌트는 인라인뷰 나 WITH절 쿼리를 메인쿼리와 합치지 말고 별개로 수행하라는 힌트임.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
::* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
::* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
::* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
::*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
::* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 병렬 처리 최적화 ===&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;(중요) 실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]]&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1698</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1698"/>
		<updated>2026-01-26T02:19:13Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 조인 순서 및 방법 제어 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::- NO_MERGE 힌트는 인라인뷰 나 WITH절 쿼리를 메인쿼리와 합치지 말고 별개로 수행하라는 힌트임.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
::* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
::::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
::* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
::* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
::*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
::* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 병렬 처리 최적화 ===&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;(중요) 실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]]&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1697</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1697"/>
		<updated>2026-01-26T02:19:00Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::- NO_MERGE 힌트는 인라인뷰 나 WITH절 쿼리를 메인쿼리와 합치지 말고 별개로 수행하라는 힌트임.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
::* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
::* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
::* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
::* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
::*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
::* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 병렬 처리 최적화 ===&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;(중요) 실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]]&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1696</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1696"/>
		<updated>2026-01-26T02:17:45Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::- NO_MERGE 힌트는 인라인뷰 나 WITH절 쿼리를 메인쿼리와 합치지 말고 별개로 수행하라는 힌트임.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 병렬 처리 최적화 ===&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;(중요) 실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]]&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1695</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1695"/>
		<updated>2026-01-26T02:13:13Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* NO_MERGE 힌트 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::- NO_MERGE 힌트는 인라인뷰 나 WITH절 쿼리를 메인쿼리와 합치지 말고 별개로 수행하라는 힌트임.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1694</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1694"/>
		<updated>2026-01-26T02:12:02Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* NO_MERGE 힌트 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= &#039;&#039;&#039;NO_MERGE 힌트의 기본 개념&#039;&#039;&#039;&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1693</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1693"/>
		<updated>2026-01-26T02:11:39Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* NO_MERGE 힌트 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= NO_MERGE 힌트의 기본 개념&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1692</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1692"/>
		<updated>2026-01-26T02:11:29Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* NO_MERGE 힌트 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= NO_MERGE 힌트의 기본 개념&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
::::::- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1691</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1691"/>
		<updated>2026-01-26T02:11:16Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* NO_MERGE 힌트 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= NO_MERGE 힌트의 기본 개념&lt;br /&gt;
|내용= - Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
- 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1690</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1690"/>
		<updated>2026-01-26T02:11:02Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* NO_MERGE 힌트 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= NO_MERGE 힌트의 기본 개념&lt;br /&gt;
|내용= # Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
# 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1689</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1689"/>
		<updated>2026-01-26T02:10:48Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* NO_MERGE 힌트 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= NO_MERGE 힌트의 기본 개념&lt;br /&gt;
|내용=&lt;br /&gt;
# Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
# 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1688</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1688"/>
		<updated>2026-01-26T02:10:31Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= NO_MERGE 힌트의 기본 개념&lt;br /&gt;
|내용=# Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
# 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1687</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1687"/>
		<updated>2026-01-26T02:09:57Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* NO_MERGE 힌트를 사용하는 이유 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트를 사용하는 이유 == &lt;br /&gt;
&lt;br /&gt;
::::{{핵심&lt;br /&gt;
|제목= NO_MERGE 힌트의 기본 개념&lt;br /&gt;
|내용=# Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
# 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1686</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1686"/>
		<updated>2026-01-26T02:09:38Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* NO_MERGE 힌트를 사용하는 이유 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트를 사용하는 이유 == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::{{핵심&lt;br /&gt;
|제목= NO_MERGE 힌트의 기본 개념&lt;br /&gt;
|내용=# Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
# 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1685</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1685"/>
		<updated>2026-01-26T02:09:25Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트를 사용하는 이유 == &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= NO_MERGE 힌트의 기본 개념&lt;br /&gt;
|내용=# Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
# 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
}}&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EB%8C%80%EB%AC%B8&amp;diff=1684</id>
		<title>대문</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EB%8C%80%EB%AC%B8&amp;diff=1684"/>
		<updated>2026-01-26T02:07:33Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 튜닝 힌트 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__notoc__&lt;br /&gt;
https://dbstudy.co.kr/w/resources/assets/dbstudy_iconx1.png &lt;br /&gt;
= Welcome To DB STUDY - {{CURRENTYEAR}}.{{CURRENTMONTHNAME}}.{{CURRENTDAY}}({{CURRENTDAYNAME}}) =&lt;br /&gt;
= 전문가가 되고 싶다면 기본에 충실 하라. (Return To Basics) =&lt;br /&gt;
* {{SERVER}}&lt;br /&gt;
* 게시글 총 : {{NUMBEROFPAGES}} 건 , 사용자 : {{NUMBEROFUSERS}} 명 , &lt;br /&gt;
&amp;lt;p sizes=&amp;quot;(max-width: 600px) 480px,800px&amp;quot;&amp;gt;&lt;br /&gt;
https://dbstudy.co.kr/w/images/dbstudy_logo.jpg&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
{{틀:타이틀 라운드&lt;br /&gt;
|제목=[[:Category:oracle|오라클]]: {{PAGESINCATEGORY: oracle}} 건 ,  [[:Category:postgresql|PostgreSql]] : {{PAGESINCATEGORY: postgresql}} 건 ,  [[:Category:mysql|MySQL]]: {{PAGESINCATEGORY: mysql}} 건,  [[:Category:linux|LINUX]]: {{PAGESINCATEGORY: linux}} 건&lt;br /&gt;
|아이콘=emoji_objects&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= ORACLE =&lt;br /&gt;
== [[ORACLE SQL 튜닝]] ==&lt;br /&gt;
=== [[튜닝 개론]]===&lt;br /&gt;
:::# [[카디널리티 와 셀렉티비티|카디널리티(cardinality) 와 셀렉티비티(선택도,selectivity)]]&lt;br /&gt;
:::# [[성능을 고려한 설계]]&lt;br /&gt;
:::# [[효율적인 SQL 작성법]]&lt;br /&gt;
&lt;br /&gt;
=== [[튜닝 환경 구축]] ===&lt;br /&gt;
:::# [[DBMS_XPLAN 사용법]]&lt;br /&gt;
:::# [[REAL PLAN 사용법]]&lt;br /&gt;
:::# [[SQL 트레이스 방법]]&lt;br /&gt;
&lt;br /&gt;
=== [[인덱스 설계]] ===&lt;br /&gt;
:::# [[인덱스 아키텍처]]&lt;br /&gt;
:::# [[오라클 인덱스 종류|인덱스 종류]]&lt;br /&gt;
:::# [[엑세스 패스]]&lt;br /&gt;
&lt;br /&gt;
=== [[옵티마이져]] ===&lt;br /&gt;
==== [[JPPD(Join Predicate PushDown,조인절 PUSHDOWN)]]====&lt;br /&gt;
==== [[View pushed predicate (조건절 PUSHDOWN)]]====&lt;br /&gt;
&lt;br /&gt;
=== [[튜닝 힌트]] ===&lt;br /&gt;
:::# [[튜닝 힌트 no merge|NO_MERGE 힌트]]&lt;br /&gt;
&lt;br /&gt;
=== [[대용량 데이터 튜닝]] ===&lt;br /&gt;
==== [[병렬 쿼리 튜닝]] ====&lt;br /&gt;
=== [[ORACLE 튜닝 대상 조회]] ===&lt;br /&gt;
=== [[성능 문제 식별 방법론과 튜닝 접근법]]===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== [[ORACLE 아키텍쳐의 이해]] ==&lt;br /&gt;
=== [[테이블 조인 방식|오라클 조인 과 알고리즘 ]] ===&lt;br /&gt;
==== [[NL 조인]]====&lt;br /&gt;
==== [[HASH 조인]]====&lt;br /&gt;
==== [[MERGE 조인|SORT MERGE 조인]]====&lt;br /&gt;
==== [[세미조인]] ====&lt;br /&gt;
==== [[안티조인]] ====&lt;br /&gt;
=== [[파라미터 설계]] ===&lt;br /&gt;
=== [[오라클 테이블의 구조]]===&lt;br /&gt;
=== [[오라클 파티션테이블의 구조]] ===&lt;br /&gt;
=== [[데이터 블럭의 구조]] ===&lt;br /&gt;
=== [[오라클 컬럼의 구조]] ===&lt;br /&gt;
==== [[오라클 컬럼의 저장순서]] ====&lt;br /&gt;
==== [[컬럼의 순서가 변경시 ROW의 물리적 구조변화|컬럼 순서 변경시 ROW의 물리구조 변화]]====&lt;br /&gt;
==== [[오라클 컬럼저장 방식 개선 (12c 업그레이드) ]] ====&lt;br /&gt;
=== [[오라클 인덱스의 구조]] ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= [[DBA_수행_방법론_(공공/대기업_SI_프로젝트)]]=&lt;br /&gt;
== [[DBA_수행_방법론_(공공/대기업_SI_프로젝트)#개요|개요]] ==&lt;br /&gt;
== [[단계별 수행 방법론]] ==&lt;br /&gt;
=== [[분석 단계]] ===&lt;br /&gt;
==== [[산출물]] ====&lt;br /&gt;
==== [[주요 작업 TASK]] ====&lt;br /&gt;
=== [[설계 단계]] ===&lt;br /&gt;
==== [[산출물]] ====&lt;br /&gt;
==== [[주요 작업 TASK]] ====&lt;br /&gt;
=== [[구축 단계]] ===&lt;br /&gt;
==== [[산출물]] ====&lt;br /&gt;
==== [[주요 작업 TASK]] ====&lt;br /&gt;
=== [[테스트 단계]] ===&lt;br /&gt;
==== [[산출물]] ====&lt;br /&gt;
==== [[주요 작업 TASK]] ====&lt;br /&gt;
=== [[전개 단계]] ===&lt;br /&gt;
==== [[산출물]] ====&lt;br /&gt;
==== [[주요 작업 TASK]] ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EB%8C%80%EB%AC%B8&amp;diff=1683</id>
		<title>대문</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EB%8C%80%EB%AC%B8&amp;diff=1683"/>
		<updated>2026-01-26T02:07:18Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* 튜닝 힌트 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__notoc__&lt;br /&gt;
https://dbstudy.co.kr/w/resources/assets/dbstudy_iconx1.png &lt;br /&gt;
= Welcome To DB STUDY - {{CURRENTYEAR}}.{{CURRENTMONTHNAME}}.{{CURRENTDAY}}({{CURRENTDAYNAME}}) =&lt;br /&gt;
= 전문가가 되고 싶다면 기본에 충실 하라. (Return To Basics) =&lt;br /&gt;
* {{SERVER}}&lt;br /&gt;
* 게시글 총 : {{NUMBEROFPAGES}} 건 , 사용자 : {{NUMBEROFUSERS}} 명 , &lt;br /&gt;
&amp;lt;p sizes=&amp;quot;(max-width: 600px) 480px,800px&amp;quot;&amp;gt;&lt;br /&gt;
https://dbstudy.co.kr/w/images/dbstudy_logo.jpg&lt;br /&gt;
&amp;lt;/p&amp;gt;&lt;br /&gt;
{{틀:타이틀 라운드&lt;br /&gt;
|제목=[[:Category:oracle|오라클]]: {{PAGESINCATEGORY: oracle}} 건 ,  [[:Category:postgresql|PostgreSql]] : {{PAGESINCATEGORY: postgresql}} 건 ,  [[:Category:mysql|MySQL]]: {{PAGESINCATEGORY: mysql}} 건,  [[:Category:linux|LINUX]]: {{PAGESINCATEGORY: linux}} 건&lt;br /&gt;
|아이콘=emoji_objects&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= ORACLE =&lt;br /&gt;
== [[ORACLE SQL 튜닝]] ==&lt;br /&gt;
=== [[튜닝 개론]]===&lt;br /&gt;
:::# [[카디널리티 와 셀렉티비티|카디널리티(cardinality) 와 셀렉티비티(선택도,selectivity)]]&lt;br /&gt;
:::# [[성능을 고려한 설계]]&lt;br /&gt;
:::# [[효율적인 SQL 작성법]]&lt;br /&gt;
&lt;br /&gt;
=== [[튜닝 환경 구축]] ===&lt;br /&gt;
:::# [[DBMS_XPLAN 사용법]]&lt;br /&gt;
:::# [[REAL PLAN 사용법]]&lt;br /&gt;
:::# [[SQL 트레이스 방법]]&lt;br /&gt;
&lt;br /&gt;
=== [[인덱스 설계]] ===&lt;br /&gt;
:::# [[인덱스 아키텍처]]&lt;br /&gt;
:::# [[오라클 인덱스 종류|인덱스 종류]]&lt;br /&gt;
:::# [[엑세스 패스]]&lt;br /&gt;
&lt;br /&gt;
=== [[옵티마이져]] ===&lt;br /&gt;
==== [[JPPD(Join Predicate PushDown,조인절 PUSHDOWN)]]====&lt;br /&gt;
==== [[View pushed predicate (조건절 PUSHDOWN)]]====&lt;br /&gt;
&lt;br /&gt;
=== [[튜닝 힌트]] ===&lt;br /&gt;
# [[튜닝 힌트 no merge|NO_MERGE 힌트]]&lt;br /&gt;
&lt;br /&gt;
=== [[대용량 데이터 튜닝]] ===&lt;br /&gt;
==== [[병렬 쿼리 튜닝]] ====&lt;br /&gt;
=== [[ORACLE 튜닝 대상 조회]] ===&lt;br /&gt;
=== [[성능 문제 식별 방법론과 튜닝 접근법]]===&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== [[ORACLE 아키텍쳐의 이해]] ==&lt;br /&gt;
=== [[테이블 조인 방식|오라클 조인 과 알고리즘 ]] ===&lt;br /&gt;
==== [[NL 조인]]====&lt;br /&gt;
==== [[HASH 조인]]====&lt;br /&gt;
==== [[MERGE 조인|SORT MERGE 조인]]====&lt;br /&gt;
==== [[세미조인]] ====&lt;br /&gt;
==== [[안티조인]] ====&lt;br /&gt;
=== [[파라미터 설계]] ===&lt;br /&gt;
=== [[오라클 테이블의 구조]]===&lt;br /&gt;
=== [[오라클 파티션테이블의 구조]] ===&lt;br /&gt;
=== [[데이터 블럭의 구조]] ===&lt;br /&gt;
=== [[오라클 컬럼의 구조]] ===&lt;br /&gt;
==== [[오라클 컬럼의 저장순서]] ====&lt;br /&gt;
==== [[컬럼의 순서가 변경시 ROW의 물리적 구조변화|컬럼 순서 변경시 ROW의 물리구조 변화]]====&lt;br /&gt;
==== [[오라클 컬럼저장 방식 개선 (12c 업그레이드) ]] ====&lt;br /&gt;
=== [[오라클 인덱스의 구조]] ===&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
= [[DBA_수행_방법론_(공공/대기업_SI_프로젝트)]]=&lt;br /&gt;
== [[DBA_수행_방법론_(공공/대기업_SI_프로젝트)#개요|개요]] ==&lt;br /&gt;
== [[단계별 수행 방법론]] ==&lt;br /&gt;
=== [[분석 단계]] ===&lt;br /&gt;
==== [[산출물]] ====&lt;br /&gt;
==== [[주요 작업 TASK]] ====&lt;br /&gt;
=== [[설계 단계]] ===&lt;br /&gt;
==== [[산출물]] ====&lt;br /&gt;
==== [[주요 작업 TASK]] ====&lt;br /&gt;
=== [[구축 단계]] ===&lt;br /&gt;
==== [[산출물]] ====&lt;br /&gt;
==== [[주요 작업 TASK]] ====&lt;br /&gt;
=== [[테스트 단계]] ===&lt;br /&gt;
==== [[산출물]] ====&lt;br /&gt;
==== [[주요 작업 TASK]] ====&lt;br /&gt;
=== [[전개 단계]] ===&lt;br /&gt;
==== [[산출물]] ====&lt;br /&gt;
==== [[주요 작업 TASK]] ====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8&amp;diff=1682</id>
		<title>튜닝 힌트</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8&amp;diff=1682"/>
		<updated>2026-01-26T02:06:00Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{:튜닝 힌트 no merge}}&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8&amp;diff=1681</id>
		<title>튜닝 힌트</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8&amp;diff=1681"/>
		<updated>2026-01-26T02:05:48Z</updated>

		<summary type="html">&lt;p&gt;Oracle: 새 문서: {:튜닝 힌트 no merge}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{:튜닝 힌트 no merge}&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1680</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1680"/>
		<updated>2026-01-26T02:03:30Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트를 사용하는 이유 == &lt;br /&gt;
&lt;br /&gt;
## NO_MERGE 힌트의 기본 개념&lt;br /&gt;
&lt;br /&gt;
# Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
# 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
::&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1679</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1679"/>
		<updated>2026-01-26T02:03:07Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE 힌트를 사용하는 이유 == &lt;br /&gt;
&lt;br /&gt;
## NO_MERGE 힌트의 기본 개념&lt;br /&gt;
&lt;br /&gt;
# Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
# 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1678</id>
		<title>튜닝 힌트 no merge</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%ED%8A%9C%EB%8B%9D_%ED%9E%8C%ED%8A%B8_no_merge&amp;diff=1678"/>
		<updated>2026-01-26T02:02:53Z</updated>

		<summary type="html">&lt;p&gt;Oracle: 새 문서: == NO_MERGE` 힌트를 사용하는 이유 ==   ## NO_MERGE 힌트의 기본 개념  # Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함.  # 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.  &amp;lt;source lang=sql&amp;gt; -- 병합 전 (논리적 구조) SELECT * FROM (     SELECT employee_id, salary      FROM employees      WHERE department_id = 10 ) v WHERE v.salary &amp;gt; 5000;  --...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== NO_MERGE` 힌트를 사용하는 이유 == &lt;br /&gt;
&lt;br /&gt;
## NO_MERGE 힌트의 기본 개념&lt;br /&gt;
&lt;br /&gt;
# Oracle 옵티마이저는 기본적으로 뷰 병합(View Merging) 을 수행함. &lt;br /&gt;
# 이는 인라인 뷰나 WITH 절의 쿼리를 메인 쿼리와 합쳐서 하나의 쿼리 블록으로 만드는 최적화 기법.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 병합 전 (논리적 구조)&lt;br /&gt;
SELECT * FROM (&lt;br /&gt;
    SELECT employee_id, salary &lt;br /&gt;
    FROM employees &lt;br /&gt;
    WHERE department_id = 10&lt;br /&gt;
) v&lt;br /&gt;
WHERE v.salary &amp;gt; 5000;&lt;br /&gt;
&lt;br /&gt;
-- 병합 후 (실제 실행)&lt;br /&gt;
SELECT employee_id, salary&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE department_id = 10 &lt;br /&gt;
  AND salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== NO_MERGE 힌트를 사용하는 주요 이유 ===&lt;br /&gt;
==== 조인 순서 및 방법 제어 ====&lt;br /&gt;
* 뷰 병합이 일어나면 옵티마이저가 조인 순서를 재결정하는데, 이것이 비효율적일 수 있음.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ &lt;br /&gt;
       d.department_name, v.avg_salary&lt;br /&gt;
FROM departments d,&lt;br /&gt;
     (SELECT department_id, AVG(salary) avg_salary&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE d.department_id = v.department_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 뷰를 먼저 구체화(Materialization)하여 집계를 수행한 후 조인하는 것이 효율적인 경우가 많습니다.&lt;br /&gt;
&lt;br /&gt;
==== 중복 작업 방지 ====&lt;br /&gt;
* 병합 시 같은 테이블을 여러 번 접근하게 되는 경우를 방지합니다.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */&lt;br /&gt;
       v.*, t.additional_col&lt;br /&gt;
FROM large_table t,&lt;br /&gt;
     (SELECT col1, col2, COMPLEX_FUNCTION(col3) as result&lt;br /&gt;
      FROM large_table&lt;br /&gt;
      WHERE expensive_condition = &#039;Y&#039;) v&lt;br /&gt;
WHERE t.key = v.col1;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
뷰를 병합하면 `COMPLEX_FUNCTION`이나 비용이 큰 조건이 중복 실행될 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== 집계 후 필터링 강제 ====&lt;br /&gt;
* 집계를 먼저 수행한 후 조건을 적용하고 싶을 때 사용.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(summary) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT department_id, COUNT(*) cnt, AVG(salary) avg_sal&lt;br /&gt;
      FROM employees&lt;br /&gt;
      GROUP BY department_id) summary&lt;br /&gt;
WHERE summary.cnt &amp;gt; 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
병합되면 `HAVING cnt &amp;gt; 10`으로 변환되어 실행 계획이 달라질 수 있습니다.&lt;br /&gt;
&lt;br /&gt;
==== ROWNUM 처리 보존 ====&lt;br /&gt;
*  뷰 내부의 ROWNUM 로직을 보존해야 할 때 필수적입니다.&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(top_n) */&lt;br /&gt;
       e.employee_name, top_n.salary&lt;br /&gt;
FROM employees e,&lt;br /&gt;
     (SELECT employee_id, salary&lt;br /&gt;
      FROM (SELECT employee_id, salary&lt;br /&gt;
            FROM employees&lt;br /&gt;
            ORDER BY salary DESC)&lt;br /&gt;
      WHERE ROWNUM &amp;lt;= 10) top_n&lt;br /&gt;
WHERE e.employee_id = top_n.employee_id;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== 분석 함수 결과 활용 ====&lt;br /&gt;
&lt;br /&gt;
* 분석 함수(Window Function) 결과를 필터링 조건으로 사용할 때 필요.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT /*+ NO_MERGE(ranked) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT employee_id, salary,&lt;br /&gt;
             RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) rn&lt;br /&gt;
      FROM employees) ranked&lt;br /&gt;
WHERE rn &amp;lt;= 3;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[category:oracle]] &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 6. **병렬 처리 최적화**&lt;br /&gt;
&lt;br /&gt;
뷰를 독립적으로 병렬 처리하고자 할 때 유용합니다.&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
SELECT /*+ NO_MERGE(v) PARALLEL(v, 4) */&lt;br /&gt;
       *&lt;br /&gt;
FROM (SELECT /*+ PARALLEL(e, 4) */&lt;br /&gt;
             department_id, COUNT(*) cnt&lt;br /&gt;
      FROM huge_employees_table e&lt;br /&gt;
      GROUP BY department_id) v&lt;br /&gt;
WHERE v.cnt &amp;gt; 100;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 실행 계획 확인 방법&lt;br /&gt;
&lt;br /&gt;
```sql&lt;br /&gt;
-- 병합 여부 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT /*+ NO_MERGE(v) */ ...&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
실행 계획에서 `VIEW` 오퍼레이션이 보이면 뷰가 병합되지 않은 것입니다.&lt;br /&gt;
&lt;br /&gt;
## 주의사항&lt;br /&gt;
&lt;br /&gt;
- NO_MERGE를 사용하면 뷰 구체화 비용이 추가됩니다&lt;br /&gt;
- 항상 실행 계획과 실제 수행 시간을 비교해야 합니다&lt;br /&gt;
- Oracle 버전에 따라 옵티마이저 동작이 다를 수 있습니다&lt;br /&gt;
- 통계 정보가 정확해야 올바른 판단이 가능합니다&lt;br /&gt;
&lt;br /&gt;
DBA로서 튜닝 작업 시 특정 케이스에 대해 더 자세한 설명이 필요하시면 말씀해주세요!&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1677</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1677"/>
		<updated>2026-01-23T07:11:03Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Cardinality (카디널리티) 와 Selectivity (선택도) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= &amp;lt;big&amp;gt;&#039;&#039;&#039;핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&#039;&#039;&#039;&amp;lt;/big&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Cardinality (카디널리티,고유값 수)&#039;&#039;&#039;&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
 예시:&lt;br /&gt;
     성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Selectivity (선택도)&#039;&#039;&#039;&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율 (선택된 row 수 / 전체 row 수)&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
::&lt;br /&gt;
 예시:&lt;br /&gt;
     성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
     특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
&lt;br /&gt;
|내용 =실무에서 사용하는 방식&lt;br /&gt;
&lt;br /&gt;
&amp;quot;이 컬럼 카디널리티가 높아서 인덱스 효과 좋을 거야&amp;quot;&lt;br /&gt;
= &amp;quot;이 컬럼 고유값이 많아서 인덱스 효과 좋을 거야&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;성별 컬럼은 카디널리티가 2야&amp;quot;&lt;br /&gt;
= &amp;quot;성별 컬럼은 고유값이 2개야&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;카디널리티 체크해봐&amp;quot;= &amp;quot;고유값 개수 확인해봐&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1676</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1676"/>
		<updated>2026-01-23T07:10:30Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= &amp;lt;big&amp;gt;&#039;&#039;&#039;핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&#039;&#039;&#039;&amp;lt;/big&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Cardinality (카디널리티,고유값 수)&#039;&#039;&#039;&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
 예시:&lt;br /&gt;
     성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Selectivity (선택도)&#039;&#039;&#039;&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율 (선택된 row 수 / 전체 row 수)&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
::&lt;br /&gt;
 예시:&lt;br /&gt;
     성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
     특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
&lt;br /&gt;
|내용 =실무에서 사용하는 방식&lt;br /&gt;
&lt;br /&gt;
&amp;quot;이 컬럼 카디널리티가 높아서 인덱스 효과 좋을 거야&amp;quot;&lt;br /&gt;
= &amp;quot;이 컬럼 고유값이 많아서 인덱스 효과 좋을 거야&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;성별 컬럼은 카디널리티가 2야&amp;quot;&lt;br /&gt;
= &amp;quot;성별 컬럼은 고유값이 2개야&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;카디널리티 체크해봐&amp;quot;&lt;br /&gt;
= &amp;quot;고유값 개수 확인해봐&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1675</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1675"/>
		<updated>2026-01-23T07:10:10Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Cardinality (카디널리티) 와 Selectivity (선택도) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= &amp;lt;big&amp;gt;&#039;&#039;&#039;핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&#039;&#039;&#039;&amp;lt;/big&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Cardinality (카디널리티,고유값 수)&#039;&#039;&#039;&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
 예시:&lt;br /&gt;
     성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Selectivity (선택도)&#039;&#039;&#039;&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율 (선택된 row 수 / 전체 row 수)&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
::&lt;br /&gt;
 예시:&lt;br /&gt;
     성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
     특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
&lt;br /&gt;
|내용 =실무에서 사용하는 방식&lt;br /&gt;
&amp;quot;이 컬럼 카디널리티가 높아서 인덱스 효과 좋을 거야&amp;quot;&lt;br /&gt;
= &amp;quot;이 컬럼 고유값이 많아서 인덱스 효과 좋을 거야&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;성별 컬럼은 카디널리티가 2야&amp;quot;&lt;br /&gt;
= &amp;quot;성별 컬럼은 고유값이 2개야&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;카디널리티 체크해봐&amp;quot;&lt;br /&gt;
= &amp;quot;고유값 개수 확인해봐&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1674</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1674"/>
		<updated>2026-01-23T07:09:27Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Cardinality (카디널리티) 와 Selectivity (선택도) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= &amp;lt;big&amp;gt;&#039;&#039;&#039;핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&#039;&#039;&#039;&amp;lt;/big&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Cardinality (카디널리티,고유값 수)&#039;&#039;&#039;&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
 예시:&lt;br /&gt;
     성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Selectivity (선택도)&#039;&#039;&#039;&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율 (선택된 row 수 / 전체 row 수)&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
::&lt;br /&gt;
 예시:&lt;br /&gt;
     성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
     특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
&lt;br /&gt;
|내용 =&amp;quot;이 컬럼 카디널리티가 높아서 인덱스 효과 좋을 거야&amp;quot;&lt;br /&gt;
= &amp;quot;이 컬럼 고유값이 많아서 인덱스 효과 좋을 거야&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;성별 컬럼은 카디널리티가 2야&amp;quot;&lt;br /&gt;
= &amp;quot;성별 컬럼은 고유값이 2개야&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;카디널리티 체크해봐&amp;quot;&lt;br /&gt;
= &amp;quot;고유값 개수 확인해봐&amp;quot;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1673</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1673"/>
		<updated>2026-01-23T07:07:55Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Cardinality (카디널리티) 와 Selectivity (선택도) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= &amp;lt;big&amp;gt;&#039;&#039;&#039;핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&#039;&#039;&#039;&amp;lt;/big&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Cardinality (카디널리티,고유값 수)&#039;&#039;&#039;&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
 예시:&lt;br /&gt;
     성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Selectivity (선택도)&#039;&#039;&#039;&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율 (선택된 row 수 / 전체 row 수)&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
::&lt;br /&gt;
 예시:&lt;br /&gt;
     성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
     특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1672</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1672"/>
		<updated>2026-01-23T07:06:32Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Cardinality (카디널리티) 와 Selectivity (선택도) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= &amp;lt;big&amp;gt;&#039;&#039;&#039;핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&#039;&#039;&#039;&amp;lt;/big&amp;gt;&lt;br /&gt;
* &#039;&#039;&#039;Cardinality (카디널리티)&#039;&#039;&#039;&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
 예시:&lt;br /&gt;
     성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Selectivity (선택도)&#039;&#039;&#039;&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율 (선택된 row 수 / 전체 row 수)&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
::&lt;br /&gt;
 예시:&lt;br /&gt;
     성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
     특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1671</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1671"/>
		<updated>2026-01-23T07:05:53Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Cardinality (카디널리티) 와 Selectivity (선택도) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= &amp;lt;big&amp;gt;&#039;&#039;&#039;핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&#039;&#039;&#039;&amp;lt;/big&amp;gt;&lt;br /&gt;
* Cardinality (카디널리티)&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
 예시:&lt;br /&gt;
     성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Selectivity (선택도)&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율 (선택된 row 수 / 전체 row 수)&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
::&lt;br /&gt;
 예시:&lt;br /&gt;
     성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
     특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1670</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1670"/>
		<updated>2026-01-23T07:05:04Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= 핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&lt;br /&gt;
* Cardinality (카디널리티)&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
 예시:&lt;br /&gt;
     성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Selectivity (선택도)&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율 (선택된 row 수 / 전체 row 수)&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
::&lt;br /&gt;
 예시:&lt;br /&gt;
     성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
     특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1669</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1669"/>
		<updated>2026-01-23T07:04:04Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= 핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&lt;br /&gt;
* Cardinality (카디널리티)&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
 예시:&lt;br /&gt;
     성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Selectivity (선택도)&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
::&lt;br /&gt;
 예시:&lt;br /&gt;
     성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
     특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1668</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1668"/>
		<updated>2026-01-23T07:03:17Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Cardinality (카디널리티) 와 Selectivity (선택도) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= 핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&lt;br /&gt;
* Cardinality (카디널리티)&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
 예시:&lt;br /&gt;
     성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Selectivity (선택도)&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
** 예시:&lt;br /&gt;
**: 성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
**: 특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1667</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1667"/>
		<updated>2026-01-23T07:02:56Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Cardinality (카디널리티) 와 Selectivity (선택도) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= 핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&lt;br /&gt;
* Cardinality (카디널리티)&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: &lt;br /&gt;
     예시:성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Selectivity (선택도)&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
** 예시:&lt;br /&gt;
**: 성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
**: 특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1666</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1666"/>
		<updated>2026-01-23T07:02:41Z</updated>

		<summary type="html">&lt;p&gt;Oracle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= 핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&lt;br /&gt;
* Cardinality (카디널리티)&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
:: 예시:성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Selectivity (선택도)&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
** 예시:&lt;br /&gt;
**: 성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
**: 특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1665</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1665"/>
		<updated>2026-01-23T07:02:25Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Cardinality (카디널리티) 와 Selectivity (선택도) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= 핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&lt;br /&gt;
* Cardinality (카디널리티)&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
 예시:성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
     주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Selectivity (선택도)&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
** 예시:&lt;br /&gt;
**: 성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
**: 특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
	<entry>
		<id>https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1664</id>
		<title>카디널리티 와 셀렉티비티</title>
		<link rel="alternate" type="text/html" href="https://dbstudy.co.kr/w/index.php?title=%EC%B9%B4%EB%94%94%EB%84%90%EB%A6%AC%ED%8B%B0_%EC%99%80_%EC%85%80%EB%A0%89%ED%8B%B0%EB%B9%84%ED%8B%B0&amp;diff=1664"/>
		<updated>2026-01-23T07:02:07Z</updated>

		<summary type="html">&lt;p&gt;Oracle: /* Cardinality (카디널리티) 와 Selectivity (선택도) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Cardinality (카디널리티) 와 Selectivity (선택도) ==&lt;br /&gt;
{{핵심&lt;br /&gt;
|제목= 핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음&lt;br /&gt;
* Cardinality (카디널리티)&lt;br /&gt;
** 특정 연산이나 조건에서 반환되는 예상 행의 개수&lt;br /&gt;
** 절대적인 수치 (행 개수)&lt;br /&gt;
** 실행 계획의 “Rows” 컬럼에 표시됨&lt;br /&gt;
** 예시:성별 컬럼: Cardinality = 2 (남, 여)&lt;br /&gt;
       주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Selectivity (선택도)&lt;br /&gt;
** 전체 행 중에서 조건을 만족하는 행의 비율&lt;br /&gt;
** 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)&lt;br /&gt;
** 조건의 “선택적” 정도를 나타냄&lt;br /&gt;
** 예시:&lt;br /&gt;
**: 성별=&#039;남&#039;: Selectivity = 0.5 (50%)&lt;br /&gt;
**: 특정 주민번호: Selectivity = 0.000001 (0.0001%)&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
Cardinality = Total Rows × Selectivity&lt;br /&gt;
&lt;br /&gt;
Selectivity = Cardinality / Total Rows&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 실무 예제 ===&lt;br /&gt;
&lt;br /&gt;
* 예제 1: 단순 테이블&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 직원 테이블&lt;br /&gt;
CREATE TABLE employees (&lt;br /&gt;
    emp_id NUMBER,&lt;br /&gt;
    dept_id NUMBER,&lt;br /&gt;
    salary NUMBER,&lt;br /&gt;
    status VARCHAR2(20)&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
-- 통계 정보&lt;br /&gt;
-- Total Rows: 10,000명&lt;br /&gt;
-- dept_id = 10: 500명&lt;br /&gt;
-- salary &amp;gt; 5000: 3,000명&lt;br /&gt;
-- status = &#039;ACTIVE&#039;: 9,000명&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
-- Query 1&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 500 / 10,000 = 0.05 (5%)&lt;br /&gt;
* Cardinality = 500 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 2&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE salary &amp;gt; 5000;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 3,000 / 10,000 = 0.3 (30%)&lt;br /&gt;
* Cardinality = 3,000 (행)&lt;br /&gt;
&lt;br /&gt;
-- Query 3&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
SELECT * FROM employees WHERE status = &#039;ACTIVE&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Selectivity = 9,000 / 10,000 = 0.9 (90%)&lt;br /&gt;
* Cardinality = 9,000 (행)&lt;br /&gt;
&lt;br /&gt;
=== 실행 계획 확인 ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 통계 수집&lt;br /&gt;
EXEC DBMS_STATS.GATHER_TABLE_STATS(&#039;SCOTT&#039;, &#039;EMPLOYEES&#039;);&lt;br /&gt;
&lt;br /&gt;
-- 실행 계획 확인&lt;br /&gt;
EXPLAIN PLAN FOR&lt;br /&gt;
SELECT * FROM employees WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
*실행 계획 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
|   0 | SELECT STATEMENT  |           |   500 |  5000 |    10   (0)|&lt;br /&gt;
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |   500 |  5000 |    10   (0)|&lt;br /&gt;
-------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
Predicate Information:&lt;br /&gt;
   1 - filter(&amp;quot;DEPT_ID&amp;quot;=10)&lt;br /&gt;
&lt;br /&gt;
Rows = 500  ← 이것이 Cardinality&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Selectivity 계산 공식===&lt;br /&gt;
1. 등호(=) 조건&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column = value&lt;br /&gt;
&lt;br /&gt;
Selectivity = 1 / NUM_DISTINCT&lt;br /&gt;
&lt;br /&gt;
예: dept_id의 distinct 값이 20개&lt;br /&gt;
Selectivity = 1 / 20 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 범위 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column &amp;gt; value&lt;br /&gt;
&lt;br /&gt;
Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE)&lt;br /&gt;
&lt;br /&gt;
예: salary BETWEEN 3000 AND 10000&lt;br /&gt;
    조건: salary &amp;gt; 5000&lt;br /&gt;
Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
3. NULL 조건&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE column IS NULL&lt;br /&gt;
&lt;br /&gt;
Selectivity = NUM_NULLS / NUM_ROWS&lt;br /&gt;
&lt;br /&gt;
예: 10,000행 중 500개가 NULL&lt;br /&gt;
Selectivity = 500 / 10,000 = 0.05&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
4. 복합 조건 (AND)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 AND col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Selectivity(col1) × Selectivity(col2)&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%)&lt;br /&gt;
Cardinality = 10,000 × 0.005 = 50&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
5. 복합 조건 (OR)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- WHERE col1 = 10 OR col2 = &#039;A&#039;&lt;br /&gt;
&lt;br /&gt;
Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2))&lt;br /&gt;
&lt;br /&gt;
예:&lt;br /&gt;
Selectivity(col1) = 0.05&lt;br /&gt;
Selectivity(col2) = 0.1&lt;br /&gt;
Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145&lt;br /&gt;
Cardinality = 10,000 × 0.145 = 1,450&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 통계 정보에서 확인 ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity 관련 통계&lt;br /&gt;
SELECT table_name, &lt;br /&gt;
       column_name,&lt;br /&gt;
       num_distinct,     -- distinct 값 개수&lt;br /&gt;
       num_nulls,        -- NULL 개수&lt;br /&gt;
       density,          -- 1/num_distinct (Selectivity)&lt;br /&gt;
       num_rows          -- 전체 행 수&lt;br /&gt;
FROM user_tab_col_statistics&lt;br /&gt;
WHERE table_name = &#039;EMPLOYEES&#039;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과 예시:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
COLUMN_NAME  NUM_DISTINCT  NUM_NULLS  DENSITY   NUM_ROWS&lt;br /&gt;
---------------------------------------------------------&lt;br /&gt;
EMP_ID       10000         0          0.0001    10000&lt;br /&gt;
DEPT_ID      20            0          0.05      10000  ← Selectivity&lt;br /&gt;
SALARY       500           100        0.002     10000&lt;br /&gt;
STATUS       2             0          0.5       10000&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 실무에서의 중요성 ===&lt;br /&gt;
&lt;br /&gt;
1. 인덱스 생성 판단&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음&lt;br /&gt;
&lt;br /&gt;
-- 좋은 경우 (Selectivity: 0.001%)&lt;br /&gt;
CREATE INDEX idx_emp_id ON employees(emp_id);&lt;br /&gt;
-- emp_id는 고유값, 조회 시 1-2건만 반환&lt;br /&gt;
&lt;br /&gt;
-- 나쁜 경우 (Selectivity: 90%)&lt;br /&gt;
CREATE INDEX idx_status ON employees(status);&lt;br /&gt;
-- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환&lt;br /&gt;
-- Full Table Scan이 더 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. 조인 순서 결정&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- Cardinality가 작은 테이블을 먼저 처리&lt;br /&gt;
&lt;br /&gt;
SELECT /*+ LEADING(d e) */ *&lt;br /&gt;
FROM departments d&lt;br /&gt;
JOIN employees e ON d.dept_id = e.dept_id&lt;br /&gt;
WHERE d.location = &#039;SEOUL&#039;;&lt;br /&gt;
&lt;br /&gt;
-- d 테이블의 Cardinality: 10 (Selectivity 1%)&lt;br /&gt;
-- e 테이블의 Cardinality: 10000 (Selectivity 100%)&lt;br /&gt;
-- → departments를 먼저 필터링하는 것이 효율적&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. 통계 정확도 확인&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-- 실제 Cardinality vs 예상 Cardinality&lt;br /&gt;
SELECT /*+ GATHER_PLAN_STATISTICS */ *&lt;br /&gt;
FROM employees&lt;br /&gt;
WHERE dept_id = 10;&lt;br /&gt;
&lt;br /&gt;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=&amp;gt;&#039;ALLSTATS LAST&#039;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* 결과:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=sql&amp;gt;&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
| Id | Operation         | Name | Starts | E-Rows | A-Rows | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
|  0 | SELECT STATEMENT  |      |      1 |        |    520 | ...&lt;br /&gt;
|* 1 | TABLE ACCESS FULL | EMP  |      1 |    500 |    520 | ...&lt;br /&gt;
-------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
E-Rows: 500  ← 예상 Cardinality (Estimated)&lt;br /&gt;
A-Rows: 520  ← 실제 Cardinality (Actual)&lt;br /&gt;
차이: 4% (통계가 정확함)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 핵심 차이점 요약 ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
|구분     |Cardinality   |Selectivity|&lt;br /&gt;
|-------|--------------|-----------|&lt;br /&gt;
|**의미** |반환되는 행의 개수    |선택되는 행의 비율 |&lt;br /&gt;
|**단위** |행 (rows)      |비율 (0~1)   |&lt;br /&gt;
|**타입** |절대값           |상대값        |&lt;br /&gt;
|**사용처**|실행 계획, Cost 계산|조건 효율성 판단  |&lt;br /&gt;
|**예시** |500 rows      |5% (0.05)  |&lt;br /&gt;
&lt;br /&gt;
**실무 팁:** Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 줍니다!​​​​​​​​​​​​​​​​&lt;/div&gt;</summary>
		<author><name>Oracle</name></author>
	</entry>
</feed>