[PostgreSQL] νŒŒν‹°μ…”λ‹ν•˜λ©΄ λͺ» ν•˜κ²Œ λ˜λŠ” 것듀 β€” μœ λ‹ˆν¬, μ™Έλž˜ν‚€, ν–‰ 이동

νŒŒν‹°μ…”λ‹ μ‹œλ¦¬μ¦ˆ λ§ˆμ§€λ§‰μ΄λ‹€. μ•žμ˜ 두 편이 μ–»λŠ” κ²ƒμ΄μ—ˆλ‹€λ©΄ 이번 νŽΈμ€ μžƒλŠ” 것이닀. νŒŒν‹°μ…”λ‹μ„ κ²°μ •ν•˜κΈ° 전에 이 λͺ©λ‘μ„ 보고 감당할 수 μžˆλŠ”μ§€ νŒλ‹¨ν•˜λŠ” 게 λ§žλ‹€. μœ λ‹ˆν¬ μ œμ•½μ€ νŒŒν‹°μ…˜ ν‚€λ₯Ό 포함해야 ν•œλ‹€ κ°€μž₯ λ¨Όμ € λΆ€λ”ͺνžˆλŠ” 벽이닀. CREATE TABLE orders ( id bigint, created_at timestamptz NOT NULL, PRIMARY KEY (id) ) PARTITION BY RANGE (created_at); ERROR: unique constraint on partitioned table must include all partitioning columns DETAIL: PRIMARY KEY constraint on table "orders" lacks column "created_at" which is part of the partition key. μ΄μœ λŠ” ꡬ쑰에 μžˆλ‹€. μœ λ‹ˆν¬ μΈλ±μŠ€λŠ” νŒŒν‹°μ…˜λ§ˆλ‹€ λ”°λ‘œ λ§Œλ“€μ–΄μ§„λ‹€. 8μ›” νŒŒν‹°μ…˜μ˜ μΈλ±μŠ€λŠ” 8μ›” νŒŒν‹°μ…˜ μ•ˆμ—μ„œλ§Œ 쀑볡을 κ²€μ‚¬ν•œλ‹€. id = 100이 8월에도 있고 9월에도 μžˆλŠ”μ§€λŠ” 아무도 κ²€μ‚¬ν•˜μ§€ μ•ŠλŠ”λ‹€. κ·Έλž˜μ„œ PostgreSQL은 μ²˜μŒλΆ€ν„° ν—ˆμš©ν•˜μ§€ μ•ŠλŠ”λ‹€. ...

[PostgreSQL] μ‹œκ°„ 기반 νŒŒν‹°μ…˜ 운영 β€” DELETE 없이 데이터 버리기

μ§€λ‚œ νŽΈμ—μ„œ νŒŒν‹°μ…”λ‹μ˜ ν™•μ‹€ν•œ 이득은 프루닝보닀 데이터λ₯Ό νŒŒν‹°μ…˜μ§Έ λ²„λ¦¬λŠ” 데 μžˆλ‹€κ³  썼닀. 이번 νŽΈμ€ κ·Έ 운영 이야기닀. μ‹œκ°„μœΌλ‘œ λ‚˜λˆˆ νŒŒν‹°μ…˜μ„ μ–΄λ–»κ²Œ λ§Œλ“€κ³ , μ–΄λ–»κ²Œ λ–Όμ–΄λ‚΄κ³ , μ–΄λ””μ„œ 사고가 λ‚˜λŠ”μ§€. νŒŒν‹°μ…˜μ€ 미리 μžˆμ–΄μ•Ό ν•œλ‹€ 행이 λ“€μ–΄μ˜¬ λ•Œ κ·Έ 값에 λ§žλŠ” νŒŒν‹°μ…˜μ΄ μ—†μœΌλ©΄ μ‹€νŒ¨ν•œλ‹€. ERROR: no partition of relation "orders" found for row DETAIL: Partition key of the failing row contains (created_at) = (2026-10-01 00:00:00+00). 10μ›” 1일 μžμ •μ— 10μ›” νŒŒν‹°μ…˜μ΄ μ—†μœΌλ©΄ κ·Έ μˆœκ°„λΆ€ν„° λͺ¨λ“  INSERTκ°€ 이 μ—λŸ¬λ‹€. μ›” 초 μžμ •μ— μž₯μ•  λ‚˜λŠ” μ „ν˜•μ μΈ κ²½λ‘œλ‹€. ...

[PostgreSQL] νŒŒν‹°μ…”λ‹μ΄ μ„±λŠ₯을 μ˜¬λ¦¬μ§€ μ•ŠλŠ” 경우

β€œν…Œμ΄λΈ”μ΄ μ»€μ„œ νŒŒν‹°μ…”λ‹ν–ˆλ‹€"λŠ” 말을 자주 λ“£λŠ”λ‹€. 그리고 κ·Έ 뒀에 β€œκ·ΈλŸ°λ° μ•ˆ λΉ¨λΌμ‘Œλ‹€"κ°€ λ”°λΌμ˜€λŠ” κ²½μš°λ„ 자주 λ³Έλ‹€. νŒŒν‹°μ…”λ‹μ€ 쿼리λ₯Ό λΉ λ₯΄κ²Œ ν•˜λŠ” κΈ°λŠ₯이 μ•„λ‹ˆλ‹€. 쑰건에 λ§žλŠ” νŒŒν‹°μ…˜λ§Œ 읽게 ν•˜λŠ” κΈ°λŠ₯이닀. κ·Έ 쑰건이 μ•ˆ κ°–μΆ°μ§€λ©΄ 이득은 μ—†κ³  λΉ„μš©λ§Œ λ‚¨λŠ”λ‹€. νŒŒν‹°μ…˜ 프루닝 μ£Όλ¬Έ ν…Œμ΄λΈ”μ„ μ›”λ³„λ‘œ λ‚˜λˆ΄λ‹€κ³  ν•˜μž. CREATE TABLE orders ( id bigint, created_at timestamptz NOT NULL, ... ) PARTITION BY RANGE (created_at); CREATE TABLE orders_2026_08 PARTITION OF orders FOR VALUES FROM ('2026-08-01') TO ('2026-09-01'); CREATE TABLE orders_2026_09 PARTITION OF orders FOR VALUES FROM ('2026-09-01') TO ('2026-10-01'); 이 μΏΌλ¦¬λŠ” 9μ›” νŒŒν‹°μ…˜ ν•˜λ‚˜λ§Œ μ½λŠ”λ‹€. ...

[PostgreSQL] μΈλ±μŠ€κ°€ μžˆλŠ”λ° μ•ˆ μ“°λŠ” μ§„μ§œ 이유

μ‹œλ¦¬μ¦ˆ λ§ˆμ§€λ§‰μ΄λ‹€. μ•žμ˜ 두 νŽΈμ—μ„œ ν–‰ 수 좔정을 λ§žμΆ”λŠ” 이야기λ₯Ό ν–ˆλ‹€. μ΄λ²ˆμ—” 좔정이 λ§žμ•„λ„ 인덱슀λ₯Ό μ•ˆ μ“°λŠ” κ²½μš°λ‹€. 인덱슀λ₯Ό λ§Œλ“€μ—ˆλŠ”λ° EXPLAIN에 μ—¬μ „νžˆ Seq Scan이 λ‚˜μ˜¨λ‹€. μ΄λ•Œ λ¨Όμ € κ°€λ₯Ό 것이 μžˆλ‹€. ν”Œλž˜λ„ˆκ°€ 인덱슀λ₯Ό λͺ» μ“°λŠ” 건지, μ•ˆ μ“°λŠ” 건지. λͺ» μ“°λŠ” 경우 쑰건의 λͺ¨μ–‘이 μΈλ±μŠ€μ™€ μ•ˆ 맞으면 ν”Œλž˜λ„ˆλŠ” 선택지 μžμ²΄κ°€ μ—†λ‹€. μ»¬λŸΌμ— ν•¨μˆ˜λ₯Ό μ”Œμ› λ‹€. WHERE lower(email) = 'a@b.com' -- email 인덱슀 λͺ» 씀 WHERE date(created_at) = '2026-09-01' -- created_at 인덱슀 λͺ» 씀 WHERE created_at + interval '1 day' > now() μΈλ±μŠ€λŠ” email의 κ°’μœΌλ‘œ 정렬돼 μžˆμ§€ lower(email)의 κ°’μœΌλ‘œ 정렬돼 μžˆμ§€ μ•Šλ‹€. ν‘œν˜„μ‹ 인덱슀λ₯Ό λ§Œλ“€κ±°λ‚˜, 쑰건을 컬럼이 κ·ΈλŒ€λ‘œ λ‚¨λŠ” ν˜•νƒœλ‘œ λ°”κΎΌλ‹€. ...

[PostgreSQL] 두 컬럼이 μ„œλ‘œ μ–½ν˜€ 있으면 ν”Œλž˜λ„ˆλŠ” 수백 λ°° ν‹€λ¦°λ‹€

μ§€λ‚œ νŽΈμ€ 컬럼 ν•˜λ‚˜μ˜ 톡계가 ν‹€λ¦¬λŠ” κ²½μš°μ˜€λ‹€. 이번 νŽΈμ€ 컬럼 ν•˜λ‚˜ν•˜λ‚˜λŠ” μ •ν™•ν•œλ° ν•¨κ»˜ μ“°λ©΄ ν‹€λ¦¬λŠ” κ²½μš°λ‹€. 이μͺ½μ΄ 더 자주, 더 크게 λΉ—λ‚˜κ°„λ‹€. 독립 κ°€μ • μ£Όμ†Œ ν…Œμ΄λΈ”μ΄ μžˆλ‹€. sido(μ‹œλ„)와 sigungu(μ‹œκ΅°κ΅¬) 컬럼이 μžˆλ‹€. SELECT * FROM addresses WHERE sido = 'μ„œμšΈνŠΉλ³„μ‹œ' AND sigungu = '강남ꡬ'; ν”Œλž˜λ„ˆλŠ” μ΄λ ‡κ²Œ κ³„μ‚°ν•œλ‹€. sido = 'μ„œμšΈνŠΉλ³„μ‹œ'인 λΉ„μœ¨: μ΅œλΉˆκ°’ λͺ©λ‘μ—μ„œ 찾음. 20%라고 ν•˜μž. sigungu = '강남ꡬ'인 λΉ„μœ¨: μ΅œλΉˆκ°’ λͺ©λ‘μ—μ„œ 찾음. 2%라고 ν•˜μž. λ‘˜ λ‹€ λ§Œμ‘±ν•˜λŠ” λΉ„μœ¨: 20% Γ— 2% = 0.4% 그런데 κ°•λ‚¨κ΅¬λŠ” μ„œμšΈμ—λ§Œ μžˆλ‹€. sigungu = '강남ꡬ'인 행은 μ „λΆ€ sido = 'μ„œμšΈνŠΉλ³„μ‹œ'λ‹€. μ‹€μ œ λΉ„μœ¨μ€ 2%λ‹€. ν”Œλž˜λ„ˆλŠ” 5λ°° 적게 μΆ”μ •ν–ˆλ‹€. ...