PostgreSQL 인덱스 스킵 스캔

PostgreSQL index skip scan

PostgreSQL 18은 복합 B-tree의 앞 열 조건이 없어도 뒤 열 조건으로 탐색할 수 있습니다.

···
html
<div class="demo"><div class="head"><b>INDEX (region, status)</b><span>WHERE status = open</span></div><div class="stage skips"><div class="group"><strong>A</strong><div class="cell hit">open</div><div class="cell">closed</div></div><div class="group"><strong>B</strong><div class="cell hit">open</div><div class="cell">closed</div></div><div class="group"><strong>C</strong><div class="cell hit">open</div><div class="cell">closed</div></div></div><div class="foot"><span id="skipstatus">seek A / open</span><span>skip to next prefix</span></div></div>
css
*{box-sizing:border-box}.demo{width:min(96vw,820px);height:min(94vh,350px);padding:clamp(8px,2vmin,18px);border:1px solid var(--line);border-radius:14px;background:var(--surface);color:var(--fg);display:flex;flex-direction:column;gap:clamp(5px,1.5vmin,12px);font:600 clamp(12px,3.5vmin,15px)/1.25 var(--font-sans),sans-serif;overflow:hidden}.head,.foot,.row{display:flex;justify-content:space-between;align-items:center;gap:8px}.head b{color:var(--accent)}.head span,.foot,.muted{color:var(--muted)}.stage{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;gap:8px}.cell,.pill{border:1px solid var(--line);border-radius:8px;background:var(--bg);padding:clamp(4px,1.2vmin,9px);text-align:center}.pill{border-radius:999px}.on{border-color:var(--accent)!important;background:color-mix(in srgb,var(--accent) 17%,var(--surface))!important;color:var(--fg)!important}.bad{border-color:#e16a5d!important;background:color-mix(in srgb,#e16a5d 18%,var(--surface))!important}.foot{font-size:clamp(12px,3vmin,14px)}.skips{justify-content:space-around}.group{display:grid;gap:5px;min-width:27%;text-align:center}.group strong{color:var(--muted)}.group .cell{padding:4px}.hit{transition:.3s}@media(max-width:400px){.skips{gap:3px}.group{min-width:30%}}
js
let n=0;function tick(){document.querySelectorAll('.hit').forEach((e,i)=>e.classList.toggle('on',i===n));document.getElementById('skipstatus').textContent='seek '+['A','B','C'][n]+' / open';n=(n+1)%3}tick();const t=setInterval(tick,1100);document.querySelector('.demo').onclick=()=>{clearInterval(t);tick()}

복합 B-tree 인덱스는 앞 열 순서가 중요합니다. PostgreSQL 18의 스킵 스캔은 앞 열에 등호 조건이 없어도 뒤 열 조건을 활용할 수 있는 경우 인덱스 탐색을 반복합니다.

데모는 지역 A, B, C의 인덱스 구간을 넘나들며 status=open인 키만 찾습니다. 항상 선택되는 계획은 아니며 데이터 분포와 비용에 따라 순차 스캔이 더 나을 수도 있습니다.

언제 쓰나

복합 인덱스의 뒤 열만 필터링하는 쿼리에서 실행 계획을 확인할 때 참고합니다.

페이지로 열기 ↗