Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

ν…Œμ΄λΈ”κ³Ό μΈλ±μŠ€μ— λŒ€ν•œ 팽창의 영ν–₯은 널리 μ•Œλ €μ Έ 있으며 Postgresμ—λ§Œ μ‘΄μž¬ν•˜λŠ” 것이 μ•„λ‹™λ‹ˆλ‹€. VACUUM FULLμ΄λ‚˜ CLUSTER와 같이 μ¦‰μ‹œ μ²˜λ¦¬ν•  수 μžˆλŠ” 방법이 μžˆμ§€λ§Œ μž‘λ™ 쀑에 ν…Œμ΄λΈ”μ„ 잠그기 λ•Œλ¬Έμ— 항상 μ‚¬μš©ν•  μˆ˜λŠ” μ—†μŠ΅λ‹ˆλ‹€.

이 κΈ°μ‚¬μ—λŠ” 팽창이 μ–΄λ–»κ²Œ λ°œμƒν•˜λŠ”μ§€, μ–΄λ–»κ²Œ λŒ€μ²˜ν•  수 μžˆλŠ”μ§€, μ§€μ—°λœ μ œμ•½ 쑰건 및 pg_repack ν™•μž₯ μ‚¬μš© μ‹œ λ°œμƒν•˜λŠ” λ¬Έμ œμ— λŒ€ν•œ κ°„λ‹¨ν•œ 이둠이 ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

이 글은 λ‹€μŒμ„ λ°”νƒ•μœΌλ‘œ μž‘μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€. λ‚˜μ˜ μ—°μ„€ PgConf.Russia 2020μ—μ„œ.

νŒ½λ§Œκ°μ€ μ™œ λ°œμƒν•˜λ‚˜μš”?

PostgresλŠ” 닀쀑 버전 λͺ¨λΈ(MVCC). κ·Έ λ³Έμ§ˆμ€ ν…Œμ΄λΈ”μ˜ 각 행이 μ—¬λŸ¬ 버전을 κ°€μ§ˆ 수 μžˆλŠ” 반면 νŠΈλžœμž­μ…˜μ€ μ΄λŸ¬ν•œ 버전 쀑 ν•˜λ‚˜λ§Œ λ³Ό 수 μžˆμ§€λ§Œ λ°˜λ“œμ‹œ λ™μΌν•œ 버전은 μ•„λ‹ˆλΌλŠ” κ²ƒμž…λ‹ˆλ‹€. 이λ₯Ό 톡해 μ—¬λŸ¬ νŠΈλžœμž­μ…˜μ΄ λ™μ‹œμ— μž‘λ™ν•˜κ³  사싀상 μ„œλ‘œ 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λΆ„λͺ…νžˆ μ΄λŸ¬ν•œ 버전은 λͺ¨λ‘ μ €μž₯λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€. PostgresλŠ” νŽ˜μ΄μ§€ λ‹¨μœ„λ‘œ λ©”λͺ¨λ¦¬λ₯Ό μ‚¬μš©ν•˜λ©°, νŽ˜μ΄μ§€λŠ” λ””μŠ€ν¬μ—μ„œ μ½κ±°λ‚˜ μ“Έ 수 μžˆλŠ” μ΅œμ†Œ 데이터 μ–‘μž…λ‹ˆλ‹€. 이것이 μ–΄λ–»κ²Œ μΌμ–΄λ‚˜λŠ”μ§€ μ΄ν•΄ν•˜κΈ° μœ„ν•΄ μž‘μ€ 예λ₯Ό μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

μ—¬λŸ¬ λ ˆμ½”λ“œλ₯Ό μΆ”κ°€ν•œ ν…Œμ΄λΈ”μ΄ μžˆλ‹€κ³  κ°€μ •ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. ν…Œμ΄λΈ”μ΄ μ €μž₯된 파일의 첫 번째 νŽ˜μ΄μ§€μ— μƒˆλ‘œμš΄ 데이터가 λ‚˜νƒ€λ‚¬μŠ΅λ‹ˆλ‹€. μ΄λŠ” 컀밋 ν›„ λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” 라이브 λ²„μ „μ˜ ν–‰μž…λ‹ˆλ‹€(λ‹¨μˆœν™”λ₯Ό μœ„ν•΄ 격리 μˆ˜μ€€μ΄ μ»€λ°‹λœ 읽기라고 κ°€μ •ν•©λ‹ˆλ‹€).

Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

그런 λ‹€μŒ ν•­λͺ© 쀑 ν•˜λ‚˜λ₯Ό μ—…λ°μ΄νŠΈν•˜μ—¬ 이전 버전을 더 이상 관련이 μ—†λŠ” κ²ƒμœΌλ‘œ ν‘œμ‹œν–ˆμŠ΅λ‹ˆλ‹€.

Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

λ‹¨κ³„λ³„λ‘œ ν–‰ 버전을 μ—…λ°μ΄νŠΈν•˜κ³  μ‚­μ œν•˜λ©΄μ„œ λ°μ΄ν„°μ˜ μ•½ 절반이 "μ“°λ ˆκΈ°"인 νŽ˜μ΄μ§€κ°€ νƒ„μƒν–ˆμŠ΅λ‹ˆλ‹€. 이 λ°μ΄ν„°λŠ” μ–΄λ–€ κ±°λž˜μ—λ„ ν‘œμ‹œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

Postgresμ—λŠ” λ©”μ»€λ‹ˆμ¦˜μ΄ μžˆμŠ΅λ‹ˆλ‹€ 진곡, 더 이상 μ‚¬μš©λ˜μ§€ μ•ŠλŠ” 버전을 μ •λ¦¬ν•˜κ³  μƒˆ 데이터λ₯Ό μœ„ν•œ 곡간을 λ§Œλ“­λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μΆ©λΆ„νžˆ 적극적으둜 κ΅¬μ„±λ˜μ§€ μ•Šμ•˜κ±°λ‚˜ λ‹€λ₯Έ ν…Œμ΄λΈ”μ—μ„œ μž‘μ—… 쀑이면 "가비지 데이터"κ°€ λ‚¨κ²Œ 되며 μƒˆ 데이터λ₯Ό μœ„ν•΄ μΆ”κ°€ νŽ˜μ΄μ§€λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

λ”°λΌμ„œ 이 μ˜ˆμ—μ„œλŠ” νŠΉμ • μ‹œμ μ— ν…Œμ΄λΈ”μ΄ XNUMXνŽ˜μ΄μ§€λ‘œ κ΅¬μ„±λ˜μ§€λ§Œ κ·Έ 쀑 μ ˆλ°˜μ—λ§Œ 라이브 데이터가 ν¬ν•¨λ©λ‹ˆλ‹€. 결과적으둜 ν…Œμ΄λΈ”μ— μ•‘μ„ΈμŠ€ν•  λ•Œ ν•„μš”ν•œ 것보닀 훨씬 λ§Žμ€ 데이터λ₯Ό 읽게 λ©λ‹ˆλ‹€.

Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

이제 VACUUM이 κ΄€λ ¨ μ—†λŠ” ν–‰ 버전을 λͺ¨λ‘ μ‚­μ œν•˜λ”λΌλ„ 상황은 크게 κ°œμ„ λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μƒˆ 행을 μœ„ν•œ νŽ˜μ΄μ§€ λ˜λŠ” 전체 νŽ˜μ΄μ§€μ— μ—¬μœ  곡간이 μžˆμ§€λ§Œ μ—¬μ „νžˆ ν•„μš”ν•œ 것보닀 더 λ§Žμ€ 데이터λ₯Ό μ½μŠ΅λ‹ˆλ‹€.
그런데 μ™„μ „νžˆ 빈 νŽ˜μ΄μ§€(이 μ˜ˆμ—μ„œλŠ” 두 번째 νŽ˜μ΄μ§€)κ°€ 파일 끝에 있으면 VACUUM이 ν•΄λ‹Ή νŽ˜μ΄μ§€λ₯Ό μž˜λΌλ‚Ό 수 μžˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이제 κ·Έλ…€λŠ” 쀑간에 μžˆμœΌλ―€λ‘œ κ·Έλ…€μ™€λŠ” 아무것도 ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

μ΄λ ‡κ²Œ λΉ„μ–΄ μžˆκ±°λ‚˜ 맀우 ν¬λ°•ν•œ νŽ˜μ΄μ§€μ˜ μˆ˜κ°€ λ§Žμ•„μ§€λ©΄ 이λ₯Ό 팽창이라고 ν•˜λ©° μ„±λŠ₯에 영ν–₯을 미치기 μ‹œμž‘ν•©λ‹ˆλ‹€.

μœ„μ—μ„œ μ„€λͺ…ν•œ λͺ¨λ“  것은 ν…Œμ΄λΈ”μ—μ„œ λΆ€ν’€μ–΄μ˜€λ₯΄λŠ” ν˜„μƒμ˜ λ©”μ»€λ‹ˆμ¦˜μž…λ‹ˆλ‹€. μΈλ±μŠ€μ—μ„œλ„ μ΄λŠ” 거의 λ™μΌν•œ λ°©μ‹μœΌλ‘œ λ°œμƒν•©λ‹ˆλ‹€.

λΆ€ν’€μ–΄ 였λ₯΄λ‚˜μš”?

팽만감이 μžˆλŠ”μ§€ ν™•μΈν•˜λŠ” λ°©λ²•μ—λŠ” μ—¬λŸ¬ 가지가 μžˆμŠ΅λ‹ˆλ‹€. 첫 번째 μ•„μ΄λ””μ–΄λŠ” ν…Œμ΄λΈ”μ˜ ν–‰ 수, "라이브" ν–‰ 수 등에 λŒ€ν•œ λŒ€λž΅μ μΈ 정보가 ν¬ν•¨λœ λ‚΄λΆ€ Postgres 톡계λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. μΈν„°λ„·μ—μ„œ κΈ°μ„± 슀크립트의 λ‹€μ–‘ν•œ λ³€ν˜•μ„ 찾을 수 μžˆμŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” 기초둜 μ‚Όμ•˜μŠ΅λ‹ˆλ‹€ 슀크립트 ν† μŠ€νŠΈ 및 팽창 btree μΈλ±μŠ€μ™€ ν•¨κ»˜ 팽창 ν…Œμ΄λΈ”μ„ 평가할 수 μžˆλŠ” PostgreSQL μ „λ¬Έκ°€μ˜ κΈ€μž…λ‹ˆλ‹€. κ²½ν—˜μƒ 였λ₯˜λŠ” 10~20%μž…λ‹ˆλ‹€.

또 λ‹€λ₯Έ 방법은 ν™•μž₯ ν”„λ‘œκ·Έλž¨μ„ μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. pgstattuple, νŽ˜μ΄μ§€ λ‚΄λΆ€λ₯Ό μ‚΄νŽ΄λ³΄κ³  μ˜ˆμƒ 및 μ •ν™•ν•œ 팽창 값을 λͺ¨λ‘ 얻을 수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 두 번째 κ²½μš°μ—λŠ” 전체 ν…Œμ΄λΈ”μ„ μŠ€μΊ”ν•΄μ•Ό ν•©λ‹ˆλ‹€.

μš°λ¦¬λŠ” μ΅œλŒ€ 20%의 μž‘μ€ 팽창 값을 ν—ˆμš© κ°€λŠ₯ν•œ κ²ƒμœΌλ‘œ κ°„μ£Όν•©λ‹ˆλ‹€. fillfactor와 μœ μ‚¬ν•˜λ‹€κ³  λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€. ν…Œμ΄λΈ” ΠΈ 인덱슀. 50% μ΄μƒμ—μ„œλŠ” μ„±λŠ₯ λ¬Έμ œκ°€ μ‹œμž‘λ  수 μžˆμŠ΅λ‹ˆλ‹€.

νŒ½λ§Œκ°μ„ ν‡΄μΉ˜ν•˜λŠ” 방법

Postgresμ—λŠ” 기본적으둜 νŒ½μ°½μ„ μ²˜λ¦¬ν•˜λŠ” μ—¬λŸ¬ 가지 방법이 μžˆμ§€λ§Œ 항상 λͺ¨λ“  μ‚¬λžŒμ—κ²Œ μ ν•©ν•œ 것은 μ•„λ‹™λ‹ˆλ‹€.

λΈ”λ‘œνŠΈκ°€ λ°œμƒν•˜μ§€ μ•Šλ„λ‘ AUTOVACUUM ꡬ성. λ˜λŠ” 더 μ •ν™•ν•˜κ²ŒλŠ” κ·€ν•˜κ°€ μˆ˜μš©ν•  수 μžˆλŠ” μˆ˜μ€€μœΌλ‘œ μœ μ§€ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. μ΄λŠ” 'μ„ μž₯의' μ‘°μ–Έμ²˜λŸΌ λ³΄μ΄μ§€λ§Œ μ‹€μ œλ‘œλŠ” 항상 λ‹¬μ„±ν•˜κΈ° μ‰¬μš΄ 것은 μ•„λ‹™λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, 데이터 μŠ€ν‚€λ§ˆλ₯Ό μ •κΈ°μ μœΌλ‘œ λ³€κ²½ν•˜μ—¬ 개발이 ν™œλ°œνžˆ 이루어지고 μžˆκ±°λ‚˜ μΌμ’…μ˜ 데이터 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜μ΄ μ§„ν–‰λ˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 결과적으둜 λ‘œλ“œ ν”„λ‘œν•„μ€ 자주 변경될 수 있으며 일반적으둜 ν…Œμ΄λΈ”λ§ˆλ‹€ λ‹€λ¦…λ‹ˆλ‹€. μ΄λŠ” μ§€μ†μ μœΌλ‘œ 미리 μž‘μ—…ν•˜κ³  각 ν…Œμ΄λΈ”μ˜ λ³€ν™”ν•˜λŠ” ν”„λ‘œν•„μ— 맞게 AUTOVACUUM을 μ‘°μ •ν•΄μ•Ό 함을 μ˜λ―Έν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λΆ„λͺ…νžˆ 이것은 쉽지 μ•ŠμŠ΅λ‹ˆλ‹€.

AUTOVACUUM이 ν…Œμ΄λΈ”μ„ λ”°λΌκ°ˆ 수 μ—†λŠ” 또 λ‹€λ₯Έ 일반적인 μ΄μœ λŠ” ν•΄λ‹Ή νŠΈλžœμž­μ…˜μ— μ‚¬μš© κ°€λŠ₯ν•œ 데이터λ₯Ό μ •λ¦¬ν•˜μ§€ λͺ»ν•˜κ²Œ ν•˜λŠ” μž₯κΈ° μ‹€ν–‰ νŠΈλžœμž­μ…˜μ΄ 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€. μ—¬κΈ°μ„œ ꢌμž₯ 사항도 λΆ„λͺ…ν•©λ‹ˆλ‹€. "맀달렀 μžˆλŠ”" νŠΈλžœμž­μ…˜μ„ μ œκ±°ν•˜κ³  ν™œμ„± νŠΈλžœμž­μ…˜ μ‹œκ°„μ„ μ΅œμ†Œν™”ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ λ‘œλ“œκ°€ OLAP와 OLTP의 ν˜Όν•©μΈ 경우 λΉˆλ²ˆν•œ μ—…λ°μ΄νŠΈμ™€ 짧은 μΏΌλ¦¬λŠ” λ¬Όλ‘  λ³΄κ³ μ„œ μž‘μ„±κ³Ό 같은 μž₯κΈ° μž‘μ—…λ„ λ™μ‹œμ— μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ μƒν™©μ—μ„œλŠ” μ„œλ‘œ λ‹€λ₯Έ κΈ°λ°˜μ— λΆ€ν•˜λ₯Ό λΆ„μ‚°μ‹œμΌœ 각 κΈ°λ°˜μ„ 더 μ„ΈλΆ€μ μœΌλ‘œ μ‘°μ •ν•  수 μžˆλ‹€λŠ” 점을 κ³ λ €ν•΄ λ³Ό κ°€μΉ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€.

또 λ‹€λ₯Έ 예 - ν”„λ‘œν•„μ΄ λ™μ’…μ΄μ§€λ§Œ λ°μ΄ν„°λ² μ΄μŠ€μ˜ λΆ€ν•˜κ°€ 맀우 높은 κ²½μš°μ—λ„ κ°€μž₯ 곡격적인 AUTOVACUUM도 λŒ€μ²˜ν•  수 μ—†μœΌλ©° 팽창이 λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€. 크기 μ‘°μ •(수직 λ˜λŠ” μˆ˜ν‰)이 μœ μΌν•œ μ†”λ£¨μ…˜μž…λ‹ˆλ‹€.

AUTOVACUUM을 μ„€μ •ν–ˆμ§€λ§Œ 뢀풀림이 계속 μ»€μ§€λŠ” μƒν™©μ—μ„œ ν•΄μ•Ό ν•  일.

νŒ€ 진곡이 가득 μ°Έ ν…Œμ΄λΈ”κ³Ό 인덱슀의 λ‚΄μš©μ„ λ‹€μ‹œ μž‘μ„±ν•˜κ³  κ΄€λ ¨ λ°μ΄ν„°λ§Œ λ‚¨κ²¨λ‘‘λ‹ˆλ‹€. 뢀풀림을 μ œκ±°ν•˜κΈ° μœ„ν•΄ μ™„λ²½ν•˜κ²Œ μž‘λ™ν•˜μ§€λ§Œ μ‹€ν–‰ 쀑에 ν…Œμ΄λΈ”μ— λŒ€ν•œ 배타적 잠금이 μΊ‘μ²˜λ˜μ–΄(AccessExclusiveLock) 이 ν…Œμ΄λΈ”μ— λŒ€ν•œ 쿼리 싀행을 ν—ˆμš©ν•˜μ§€ μ•ŠμœΌλ©° 심지어 선택도 ν—ˆμš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ„œλΉ„μŠ€ λ˜λŠ” κ·Έ 일뢀λ₯Ό 일정 μ‹œκ°„ λ™μ•ˆ(λ°μ΄ν„°λ² μ΄μŠ€ 및 ν•˜λ“œμ›¨μ–΄μ˜ 크기에 따라 μˆ˜μ‹­ λΆ„μ—μ„œ λͺ‡ μ‹œκ°„κΉŒμ§€) 쀑지할 수 μžˆλŠ” 경우 이 μ˜΅μ…˜μ΄ κ°€μž₯ μ’‹μŠ΅λ‹ˆλ‹€. μ•„μ‰½κ²Œλ„ μ˜ˆμ •λœ μœ μ§€ 관리 κΈ°κ°„ λ™μ•ˆ VACUUM FULL을 μ‹€ν–‰ν•  μ‹œκ°„μ΄ μ—†μœΌλ―€λ‘œ 이 방법은 μš°λ¦¬μ—κ²Œ μ ν•©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

νŒ€ CLUSTER VACUUM FULLκ³Ό λ™μΌν•œ λ°©μ‹μœΌλ‘œ ν…Œμ΄λΈ”μ˜ λ‚΄μš©μ„ λ‹€μ‹œ μž‘μ„±ν•˜μ§€λ§Œ λ””μŠ€ν¬μ—μ„œ 데이터가 물리적으둜 μ •λ ¬λ˜λŠ” 인덱슀λ₯Ό 지정할 수 μžˆμŠ΅λ‹ˆλ‹€(κ·ΈλŸ¬λ‚˜ λ―Έλž˜μ—λŠ” μƒˆ 행에 λŒ€ν•΄ μˆœμ„œκ°€ 보μž₯λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€). νŠΉμ • μƒν™©μ—μ„œλŠ” μΈλ±μŠ€λ³„λ‘œ μ—¬λŸ¬ λ ˆμ½”λ“œλ₯Ό μ½λŠ” μ—¬λŸ¬ 쿼리에 λŒ€ν•œ 쒋은 μ΅œμ ν™”μž…λ‹ˆλ‹€. 이 λͺ…λ Ήμ˜ 단점은 VACUUM FULLκ³Ό λ™μΌν•©λ‹ˆλ‹€. 즉, μž‘λ™ 쀑에 ν…Œμ΄λΈ”μ„ μž κΈ‰λ‹ˆλ‹€.

νŒ€ μž¬μƒ‰μΈ 이전 두 가지와 μœ μ‚¬ν•˜μ§€λ§Œ νŠΉμ • 인덱슀 λ˜λŠ” ν…Œμ΄λΈ”μ˜ λͺ¨λ“  인덱슀λ₯Ό λ‹€μ‹œ μž‘μ„±ν•©λ‹ˆλ‹€. μž κΈˆμ€ μ•½κ°„ μ•½ν•©λ‹ˆλ‹€. ν…Œμ΄λΈ”μ˜ ShareLock(μˆ˜μ •μ„ λ°©μ§€ν•˜μ§€λ§Œ 선택은 ν—ˆμš©) 및 λ‹€μ‹œ μž‘μ„±λ˜λŠ” 인덱슀의 AccessExclusiveLock(이 인덱슀λ₯Ό μ‚¬μš©ν•˜λŠ” 쿼리 차단)μž…λ‹ˆλ‹€. ν•˜μ§€λ§Œ Postgres 12 λ²„μ „μ—μ„œλŠ” λ§€κ°œλ³€μˆ˜κ°€ λ“±μž₯ν–ˆμŠ΅λ‹ˆλ‹€. λ™μ‹œμ—, λ ˆμ½”λ“œμ˜ λ™μ‹œ μΆ”κ°€, μˆ˜μ • λ˜λŠ” μ‚­μ œλ₯Ό μ°¨λ‹¨ν•˜μ§€ μ•Šκ³  인덱슀λ₯Ό λ‹€μ‹œ μž‘μ„±ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

이전 λ²„μ „μ˜ Postgresμ—μ„œλŠ” λ‹€μŒμ„ μ‚¬μš©ν•˜μ—¬ REINDEX CONCURRENTLY와 μœ μ‚¬ν•œ κ²°κ³Όλ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€. λ™μ‹œμ— 인덱슀 생성. 이λ₯Ό 톡해 μ—„κ²©ν•œ 잠금(병렬 쿼리λ₯Ό λ°©ν•΄ν•˜μ§€ μ•ŠλŠ” ShareUpdateExclusiveLock) 없이 인덱슀λ₯Ό μƒμ„±ν•œ λ‹€μŒ 이전 인덱슀λ₯Ό μƒˆ 인덱슀둜 κ΅μ²΄ν•˜κ³  이전 인덱슀λ₯Ό μ‚­μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό 톡해 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ λ°©ν•΄ν•˜μ§€ μ•Šκ³  인덱슀 νŒ½μ°½μ„ μ œκ±°ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 인덱슀λ₯Ό μž¬κ΅¬μΆ•ν•  λ•Œ λ””μŠ€ν¬ ν•˜μœ„ μ‹œμŠ€ν…œμ— μΆ”κ°€ λ‘œλ“œκ°€ λ°œμƒν•œλ‹€λŠ” 점을 κ³ λ €ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€.

λ”°λΌμ„œ 인덱슀의 경우 "μ¦‰μ‹œ" νŒ½μ°½μ„ μ œκ±°ν•  수 μžˆλŠ” 방법이 μžˆλ‹€λ©΄ ν…Œμ΄λΈ”μ—λŠ” 방법이 μ—†μŠ΅λ‹ˆλ‹€. λ‹€μ–‘ν•œ μ™ΈλΆ€ ν™•μž₯이 μž‘λ™ν•˜λŠ” κ³³μž…λ‹ˆλ‹€. pg_repack (μ΄μ „μ˜ pg_reorg), pgcompact, pgcompactable λ‹€λ₯Έ μ‚¬λžŒ. 이 κΈ°μ‚¬μ—μ„œλŠ” 그것듀을 λΉ„κ΅ν•˜μ§€ μ•Šκ³  pg_repack에 λŒ€ν•΄μ„œλ§Œ μ„€λͺ…ν•  κ²ƒμž…λ‹ˆλ‹€. pg_repack은 μ•½κ°„μ˜ μˆ˜μ • 후에 μš°λ¦¬κ°€ 직접 μ‚¬μš©ν•©λ‹ˆλ‹€.

pg_repack μž‘λ™ 방식

Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건
인덱슀, μ œν•œ 사항, 그리고 λΆˆν–‰ν•˜κ²Œλ„ 팽창이 ν¬ν•¨λœ μ™„μ „νžˆ 일반적인 ν…Œμ΄λΈ”μ΄ μžˆλ‹€κ³  κ°€μ •ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. pg_repack의 첫 번째 λ‹¨κ³„λŠ” μ‹€ν–‰ 쀑 λͺ¨λ“  λ³€κ²½ 사항에 λŒ€ν•œ 데이터λ₯Ό μ €μž₯ν•˜λŠ” 둜그 ν…Œμ΄λΈ”μ„ λ§Œλ“œλŠ” κ²ƒμž…λ‹ˆλ‹€. νŠΈλ¦¬κ±°λŠ” λͺ¨λ“  μ‚½μž…, μ—…λ°μ΄νŠΈ 및 μ‚­μ œμ— λŒ€ν•΄ μ΄λŸ¬ν•œ λ³€κ²½ 사항을 λ³΅μ œν•©λ‹ˆλ‹€. 그런 λ‹€μŒ ꡬ쑰상 원본 ν…Œμ΄λΈ”κ³Ό μœ μ‚¬ν•˜μ§€λ§Œ 데이터 μ‚½μž… ν”„λ‘œμ„ΈμŠ€κ°€ λŠλ €μ§€μ§€ μ•Šλ„λ‘ μΈλ±μŠ€μ™€ μ œν•œ 사항이 μ—†λŠ” ν…Œμ΄λΈ”μ΄ μƒμ„±λ©λ‹ˆλ‹€.

λ‹€μŒμœΌλ‘œ, pg_repack은 이전 ν…Œμ΄λΈ”μ˜ 데이터λ₯Ό μƒˆ ν…Œμ΄λΈ”λ‘œ μ „μ†‘ν•˜κ³  κ΄€λ ¨ μ—†λŠ” λͺ¨λ“  행을 μžλ™μœΌλ‘œ ν•„ν„°λ§ν•œ λ‹€μŒ μƒˆ ν…Œμ΄λΈ”μ— λŒ€ν•œ 인덱슀λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ λͺ¨λ“  μž‘μ—…μ„ μ‹€ν–‰ν•˜λŠ” λ™μ•ˆ λ³€κ²½ 사항이 둜그 ν…Œμ΄λΈ”μ— λˆ„μ λ©λ‹ˆλ‹€.

λ‹€μŒ λ‹¨κ³„λŠ” λ³€κ²½ 사항을 μƒˆ ν…Œμ΄λΈ”λ‘œ μ „μ†‘ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. λ§ˆμ΄κ·Έλ ˆμ΄μ…˜μ€ μ—¬λŸ¬ 번의 λ°˜λ³΅μ„ 톡해 μˆ˜ν–‰λ˜λ©° 둜그 ν…Œμ΄λΈ”μ— 20개 미만의 ν•­λͺ©μ΄ 남아 μžˆλŠ” 경우 pg_repack은 κ°•λ ₯ν•œ μž κΈˆμ„ νšλ“ν•˜κ³  μ΅œμ‹  데이터λ₯Ό λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ν•˜λ©° Postgres μ‹œμŠ€ν…œ ν…Œμ΄λΈ”μ˜ 이전 ν…Œμ΄λΈ”μ„ μƒˆ ν…Œμ΄λΈ”λ‘œ λ°”κΏ‰λ‹ˆλ‹€. 이것은 ν…Œμ΄λΈ” μž‘μ—…μ„ ν•  수 μ—†λŠ” μœ μΌν•˜κ³  맀우 짧은 μ‹œκ°„μž…λ‹ˆλ‹€. 이후 κΈ°μ‘΄ ν…Œμ΄λΈ”κ³Ό λ‘œκ·Έκ°€ μžˆλŠ” ν…Œμ΄λΈ”μ΄ μ‚­μ œλ˜κ³  파일 μ‹œμŠ€ν…œμ— μ—¬μœ  곡간이 ν™•λ³΄λ©λ‹ˆλ‹€. ν”„λ‘œμ„ΈμŠ€κ°€ μ™„λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.

μ΄λ‘ μ μœΌλ‘œλŠ” λͺ¨λ“  것이 ν›Œλ₯­ν•΄ λ³΄μ΄μ§€λ§Œ μ‹€μ œλ‘œλŠ” μ–΄λ–»κ²Œ λ κΉŒμš”? λ‘œλ“œκ°€ μ—†λŠ” μƒνƒœμ™€ λ‘œλ“œκ°€ μžˆλŠ” μƒνƒœμ—μ„œ pg_repack을 ν…ŒμŠ€νŠΈν•˜κ³  μ‘°κΈ° 쀑지(즉, Ctrl+C μ‚¬μš©) μ‹œ μž‘λ™μ„ ν™•μΈν–ˆμŠ΅λ‹ˆλ‹€. λͺ¨λ“  ν…ŒμŠ€νŠΈλŠ” κΈμ •μ μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

μš°λ¦¬λŠ” μ‹ν’ˆμ μ— κ°”λŠ”λ° λͺ¨λ“  것이 μ˜ˆμƒλŒ€λ‘œ μ§„ν–‰λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

첫 번째 νŒ¬μΌ€μ΄ν¬ 판맀

첫 번째 ν΄λŸ¬μŠ€ν„°μ—μ„œλŠ” 고유 μ œμ•½ 쑰건 μœ„λ°˜μ— λŒ€ν•œ 였λ₯˜λ₯Ό λ°›μ•˜μŠ΅λ‹ˆλ‹€.

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

이 μ œν•œμ—λŠ” μžλ™ μƒμ„±λœ 이름 index_16508이 있으며 μ΄λŠ” pg_repack에 μ˜ν•΄ μƒμ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€. ꡬ성에 ν¬ν•¨λœ 속성을 기반으둜 이에 ν•΄λ‹Ήν•˜λŠ” "우리의" μ œμ•½ 쑰건을 κ²°μ •ν–ˆμŠ΅λ‹ˆλ‹€. λ¬Έμ œλŠ” 이것이 μ™„μ „νžˆ 일반적인 μ œν•œμ΄ μ•„λ‹ˆλΌ μ§€μ—°λœ μ œν•œμ΄λΌλŠ” κ²ƒμœΌλ‘œ λ°ν˜€μ‘ŒμŠ΅λ‹ˆλ‹€(μ§€μ—°λœ μ œμ•½), 즉. ν•΄λ‹Ή 확인은 sql λͺ…령보닀 λ‚˜μ€‘μ— μˆ˜ν–‰λ˜λ―€λ‘œ 예기치 μ•Šμ€ κ²°κ³Όκ°€ λ°œμƒν•©λ‹ˆλ‹€.

μ§€μ—°λœ μ œμ•½μ‘°κ±΄: 이것이 ν•„μš”ν•œ μ΄μœ μ™€ μž‘λ™ 방식

μ§€μ—°λœ μ œν•œμ— λŒ€ν•œ μž‘μ€ 이둠.
κ°„λ‹¨ν•œ 예λ₯Ό 생각해 λ³΄κ² μŠ΅λ‹ˆλ‹€. 디렉터리에 μžˆλŠ” μžλ™μ°¨μ˜ 이름과 μˆœμ„œλΌλŠ” 두 가지 속성을 가진 μžλ™μ°¨μ— λŒ€ν•œ ν…Œμ΄λΈ” μ°Έμ‘° 책이 μžˆμŠ΅λ‹ˆλ‹€.
Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

create table cars
(
  name text constraint pk_cars primary key,
  ord integer not null constraint uk_cars unique
);



첫 번째 μ°¨λŸ‰κ³Ό 두 번째 μ°¨λŸ‰μ„ ꡐ체해야 ν•œλ‹€κ³  κ°€μ •ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. κ°„λ‹¨ν•œ 해결책은 첫 번째 값을 두 번째 κ°’μœΌλ‘œ μ—…λ°μ΄νŠΈν•˜κ³  두 번째 값을 첫 번째 κ°’μœΌλ‘œ μ—…λ°μ΄νŠΈν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

begin;
  update cars set ord = 2 where name = 'audi';
  update cars set ord = 1 where name = 'bmw';
commit;

ν•˜μ§€λ§Œ 이 μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜λ©΄ ν…Œμ΄λΈ”μ˜ κ°’ μˆœμ„œκ°€ κ³ μœ ν•˜κΈ° λ•Œλ¬Έμ— μ œμ•½ 쑰건 μœ„λ°˜μ΄ μ˜ˆμƒλ©λ‹ˆλ‹€.

[23305] ERROR: duplicate key value violates unique constraint β€œuk_cars”
Detail: Key (ord)=(2) already exists.

μ–΄λ–»κ²Œ λ‹€λ₯΄κ²Œ ν•  수 μžˆλ‚˜μš”? μ˜΅μ…˜ 1: ν…Œμ΄λΈ”μ— μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 것이 보μž₯λ˜λŠ” 주문에 λŒ€μ²΄ 값을 μΆ”κ°€ν•©λ‹ˆλ‹€(예: "-XNUMX"). ν”„λ‘œκ·Έλž˜λ°μ—μ„œλŠ” 이λ₯Ό "두 λ³€μˆ˜μ˜ 값을 μ„Έ 번째 λ³€μˆ˜λ‘œ κ΅ν™˜"이라고 ν•©λ‹ˆλ‹€. 이 λ°©λ²•μ˜ μœ μΌν•œ 단점은 μΆ”κ°€ μ—…λ°μ΄νŠΈμž…λ‹ˆλ‹€.

μ˜΅μ…˜ 1: μˆœμ„œ 값에 μ •μˆ˜ λŒ€μ‹  뢀동 μ†Œμˆ˜μ  데이터 μœ ν˜•μ„ μ‚¬μš©ν•˜λ„λ‘ ν…Œμ΄λΈ”μ„ λ‹€μ‹œ λ””μžμΈν•©λ‹ˆλ‹€. 그런 λ‹€μŒ 값을 2.5μ—μ„œ XNUMX둜 μ—…λ°μ΄νŠΈν•˜λ©΄ 첫 번째 ν•­λͺ©μ΄ 두 번째 ν•­λͺ©κ³Ό μ„Έ 번째 ν•­λͺ© 사이에 μžλ™μœΌλ‘œ "λŒ€κΈ°"λ©λ‹ˆλ‹€. 이 μ†”λ£¨μ…˜μ€ μž‘λ™ν•˜μ§€λ§Œ 두 가지 μ œν•œ 사항이 μžˆμŠ΅λ‹ˆλ‹€. 첫째, 값이 μΈν„°νŽ˜μ΄μŠ€ μ–΄λ”˜κ°€μ—μ„œ μ‚¬μš©λ˜λ©΄ μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ‘˜μ§Έ, 데이터 μœ ν˜•μ˜ 정밀도에 따라 λͺ¨λ“  λ ˆμ½”λ“œμ˜ 값을 λ‹€μ‹œ κ³„μ‚°ν•˜κΈ° 전에 κ°€λŠ₯ν•œ μ‚½μž… μˆ˜κ°€ μ œν•œλ©λ‹ˆλ‹€.

μ˜΅μ…˜ XNUMX: 컀밋 μ‹œμ—λ§Œ ν™•μΈλ˜λ„λ‘ μ œμ•½ 쑰건을 μ—°κΈ°ν•©λ‹ˆλ‹€.

create table cars
(
  name text constraint pk_cars primary key,
  ord integer not null constraint uk_cars unique deferrable initially deferred
);

초기 μš”μ²­μ˜ λ…Όλ¦¬λŠ” 컀밋 μ‹œ λͺ¨λ“  값이 κ³ μœ ν•¨μ„ 보μž₯ν•˜λ―€λ‘œ 성곡할 κ²ƒμž…λ‹ˆλ‹€.

μœ„μ—μ„œ λ…Όμ˜ν•œ μ˜ˆλŠ” λ¬Όλ‘  맀우 ν•©μ„±μ μ΄μ§€λ§Œ 아이디어λ₯Ό λ“œλŸ¬λƒ…λ‹ˆλ‹€. 우리 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œλŠ” μ§€μ—°λœ μ œμ•½ 쑰건을 μ‚¬μš©ν•˜μ—¬ μ‚¬μš©μžκ°€ λ³΄λ“œμ˜ 곡유 μœ„μ ― κ°œμ²΄μ™€ λ™μ‹œμ— μž‘μ—…ν•  λ•Œ μΆ©λŒμ„ ν•΄κ²°ν•˜λŠ” 논리λ₯Ό κ΅¬ν˜„ν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ μ œν•œμ„ μ‚¬μš©ν•˜λ©΄ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ½”λ“œλ₯Ό μ’€ 더 κ°„λ‹¨ν•˜κ²Œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

일반적으둜 μ œμ•½ 쑰건 μœ ν˜•μ— 따라 Postgresμ—λŠ” ν–‰, νŠΈλžœμž­μ…˜ 및 ν‘œν˜„μ‹ μˆ˜μ€€μ΄λΌλŠ” μ„Έ 가지 μˆ˜μ€€μ˜ μ„ΈλΆ„μ„± 검사가 μžˆμŠ΅λ‹ˆλ‹€.
Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건
좜처 : 베그리프

CHECK 및 NOT NULL은 항상 ν–‰ μˆ˜μ€€μ—μ„œ ν™•μΈλ˜λ©°, ν‘œμ—μ„œ λ³Ό 수 μžˆλ“―μ΄ λ‹€λ₯Έ μ œν•œ 사항에 λŒ€ν•΄μ„œλŠ” λ‹€λ₯Έ μ˜΅μ…˜μ΄ μžˆμŠ΅λ‹ˆλ‹€. 더 읽어보싀 수 μžˆμŠ΅λ‹ˆλ‹€ 여기에.

κ°„λ‹¨νžˆ μš”μ•½ν•˜μžλ©΄, λ‹€μ–‘ν•œ μƒν™©μ—μ„œ μ§€μ—°λœ μ œμ•½ 쑰건은 더 읽기 μ‰¬μš΄ μ½”λ“œμ™€ 더 적은 λͺ…령을 μ œκ³΅ν•©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 였λ₯˜κ°€ λ°œμƒν•˜λŠ” μˆœκ°„κ³Ό 였λ₯˜λ₯Ό λ°œκ²¬ν•˜λŠ” μˆœκ°„μ€ μ‹œκ°„μƒ λΆ„λ¦¬λ˜μ–΄ 있기 λ•Œλ¬Έμ— 디버깅 과정을 λ³΅μž‘ν•˜κ²Œ λ§Œλ“€μ–΄ 이에 λŒ€ν•œ λŒ€κ°€λ₯Ό μΉ˜λŸ¬μ•Ό ν•©λ‹ˆλ‹€. 또 λ‹€λ₯Έ κ°€λŠ₯ν•œ λ¬Έμ œλŠ” μš”μ²­μ— μ§€μ—°λœ μ œμ•½ 쑰건이 ν¬ν•¨λœ 경우 μŠ€μΌ€μ€„λŸ¬κ°€ 항상 졜적의 κ³„νšμ„ ꡬ성할 수 μ—†λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

pg_repack κ°œμ„ 

μš°λ¦¬λŠ” μ§€μ—°λœ μ œμ•½μ‘°κ±΄μ΄ 무엇인지 λ‹€λ£¨μ—ˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 그것이 우리의 λ¬Έμ œμ™€ μ–΄λ–€ 관련이 μžˆμŠ΅λ‹ˆκΉŒ? 이전에 받은 였λ₯˜λ₯Ό κΈ°μ–΅ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

둜그 ν…Œμ΄λΈ”μ—μ„œ μƒˆ ν…Œμ΄λΈ”λ‘œ 데이터가 볡사될 λ•Œ λ°œμƒν•©λ‹ˆλ‹€. 이상해 λ³΄μ΄λŠ”λ° μ™œλƒλ©΄... 둜그 ν…Œμ΄λΈ”μ˜ λ°μ΄ν„°λŠ” μ†ŒμŠ€ ν…Œμ΄λΈ”μ˜ 데이터와 ν•¨κ»˜ μ»€λ°‹λ©λ‹ˆλ‹€. μ›λž˜ ν…Œμ΄λΈ”μ˜ μ œμ•½ 쑰건을 μΆ©μ‘±ν•œλ‹€λ©΄ μ–΄λ–»κ²Œ μƒˆ ν…Œμ΄λΈ”μ˜ λ™μΌν•œ μ œμ•½ 쑰건을 μœ„λ°˜ν•  수 μžˆμŠ΅λ‹ˆκΉŒ?

μ•Œκ³  λ³΄λ‹ˆ 문제의 κ·Όλ³Έ 원인은 μ œμ•½ 쑰건이 μ•„λ‹Œ 인덱슀만 μƒμ„±ν•˜λŠ” pg_repack의 이전 단계에 μžˆμŠ΅λ‹ˆλ‹€. 이전 ν…Œμ΄λΈ”μ—λŠ” 고유 μ œμ•½ 쑰건이 μžˆμ—ˆκ³  μƒˆ ν…Œμ΄λΈ”μ—λŠ” λŒ€μ‹  고유 μΈλ±μŠ€κ°€ μƒμ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

μ—¬κΈ°μ„œ μ€‘μš”ν•œ 점은 μ œμ•½ 쑰건이 정상이고 μ§€μ—°λ˜μ§€ μ•Šμ€ 경우 λŒ€μ‹  μƒμ„±λœ 고유 μΈλ±μŠ€κ°€ 이 μ œμ•½ 쑰건과 λ™μΌν•˜λ‹€λŠ” μ μž…λ‹ˆλ‹€. Postgres의 고유 μ œμ•½ 쑰건은 고유 인덱슀λ₯Ό μƒμ„±ν•˜μ—¬ κ΅¬ν˜„λ©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 지연 μ œμ•½ 쑰건의 경우 인덱슀λ₯Ό 지연할 수 μ—†κ³  sql λͺ…령이 싀행될 λ•Œ 항상 ν™•μΈλ˜λ―€λ‘œ λ™μž‘μ΄ λ™μΌν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ 문제의 λ³Έμ§ˆμ€ κ²€μ‚¬μ˜ "지연"에 μžˆμŠ΅λ‹ˆλ‹€. μ›λž˜ ν…Œμ΄λΈ”μ—μ„œλŠ” 컀밋 μ‹œ λ°œμƒν•˜κ³  μƒˆ ν…Œμ΄λΈ”μ—μ„œλŠ” sql λͺ…령이 싀행될 λ•Œ λ°œμƒν•©λ‹ˆλ‹€. μ΄λŠ” 두 경우 λͺ¨λ‘μ—μ„œ 검사가 λ™μΌν•˜κ²Œ μˆ˜ν–‰λ˜λŠ”μ§€ 확인해야 함을 μ˜λ―Έν•©λ‹ˆλ‹€. 즉, 항상 μ§€μ—°λ˜κ±°λ‚˜ 항상 μ¦‰μ‹œ μˆ˜ν–‰λ©λ‹ˆλ‹€.

그럼 μš°λ¦¬λŠ” μ–΄λ–€ 아이디어λ₯Ό 가지고 μžˆμ—ˆλ‚˜μš”?

deferred와 μœ μ‚¬ν•œ 인덱슀 생성

첫 번째 μ•„μ΄λ””μ–΄λŠ” μ¦‰μ‹œ λͺ¨λ“œμ—μ„œ 두 검사λ₯Ό λͺ¨λ‘ μˆ˜ν–‰ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 이둜 인해 μ—¬λŸ¬ 가지 μ˜€νƒ μ œν•œμ΄ λ°œμƒν•  수 μžˆμ§€λ§Œ κ·Έ μˆ˜κ°€ 적더라도 μ΄λŸ¬ν•œ μΆ©λŒμ€ 정상적인 상황이기 λ•Œλ¬Έμ— μ‚¬μš©μžμ˜ μž‘μ—…μ— 영ν–₯을 μ£Όμ–΄μ„œλŠ” μ•ˆ λ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄ 두 λͺ…μ˜ μ‚¬μš©μžκ°€ λ™μ‹œμ— λ™μΌν•œ μœ„μ ― νŽΈμ§‘μ„ μ‹œμž‘ν•˜κ³  두 번째 μ‚¬μš©μžμ˜ ν΄λΌμ΄μ–ΈνŠΈκ°€ 첫 번째 μ‚¬μš©μžκ°€ νŽΈμ§‘ν•  수 없도둝 μœ„μ ―μ΄ 이미 μ°¨λ‹¨λ˜μ—ˆλ‹€λŠ” 정보λ₯Ό 받을 μ‹œκ°„μ΄ μ—†λŠ” κ²½μš°μ— λ°œμƒν•©λ‹ˆλ‹€. μ΄λŸ¬ν•œ μƒν™©μ—μ„œ μ„œλ²„λŠ” 두 번째 μ‚¬μš©μžλ₯Ό κ±°λΆ€ν•˜κ³  ν•΄λ‹Ή ν΄λΌμ΄μ–ΈνŠΈλŠ” λ³€κ²½ 사항을 λ‘€λ°±ν•˜κ³  μœ„μ ―μ„ μ°¨λ‹¨ν•©λ‹ˆλ‹€. μž μ‹œ ν›„ 첫 번째 μ‚¬μš©μžκ°€ νŽΈμ§‘μ„ μ™„λ£Œν•˜λ©΄ 두 번째 μ‚¬μš©μžλŠ” μœ„μ ―μ΄ 더 이상 μ°¨λ‹¨λ˜μ§€ μ•Šκ³  ν•΄λ‹Ή μž‘μ—…μ„ λ°˜λ³΅ν•  수 μžˆλ‹€λŠ” 정보λ₯Ό λ°›κ²Œ λ©λ‹ˆλ‹€.

Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

검사가 항상 μ§€μ—°λ˜μ§€ μ•ŠλŠ” λͺ¨λ“œμΈμ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ μ›λž˜ 지연 μ œμ•½ 쑰건과 μœ μ‚¬ν•œ μƒˆ 인덱슀λ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.

CREATE UNIQUE INDEX CONCURRENTLY uk_tablename__immediate ON tablename (id, index);
-- run pg_repack
DROP INDEX CONCURRENTLY uk_tablename__immediate;

ν…ŒμŠ€νŠΈ ν™˜κ²½μ—μ„œλŠ” μ˜ˆμƒλ˜λŠ” 였λ₯˜κ°€ λͺ‡ 개만 μˆ˜μ‹ λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 성곡! ν”„λ‘œλ•μ…˜ ν™˜κ²½μ—μ„œ pg_repack을 λ‹€μ‹œ μ‹€ν–‰ν–ˆλŠ”λ° ν•œ μ‹œκ°„ λ™μ•ˆ 첫 번째 ν΄λŸ¬μŠ€ν„°μ—μ„œ 5개의 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” 수용 κ°€λŠ₯ν•œ κ²°κ³Όμž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 이미 두 번째 ν΄λŸ¬μŠ€ν„°μ—μ„œλŠ” 였λ₯˜ μˆ˜κ°€ 크게 μ¦κ°€ν•˜μ—¬ pg_repack을 쀑지해야 ν–ˆμŠ΅λ‹ˆλ‹€.

μ™œ 그런 일이 μΌμ–΄λ‚¬λ‚˜μš”? 였λ₯˜κ°€ λ°œμƒν•  κ°€λŠ₯성은 λ™μ‹œμ— λ™μΌν•œ μœ„μ ―μ„ μ‚¬μš©ν•˜μ—¬ μž‘μ—…ν•˜λŠ” μ‚¬μš©μž μˆ˜μ— 따라 λ‹¬λΌμ§‘λ‹ˆλ‹€. λΆ„λͺ…νžˆ κ·Έ μˆœκ°„μ—λŠ” λ‹€λ₯Έ ν΄λŸ¬μŠ€ν„°λ³΄λ‹€ 첫 번째 ν΄λŸ¬μŠ€ν„°μ— μ €μž₯된 데이터에 λŒ€ν•œ 경쟁적 λ³€κ²½ 사항이 훨씬 μ μ—ˆμŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” 단지 "ν–‰μš΄"μ΄μ—ˆμŠ΅λ‹ˆλ‹€.

아이디어가 μž‘λ™ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. κ·Έ μ‹œμ μ—μ„œ μš°λ¦¬λŠ” 두 가지 λ‹€λ₯Έ μ†”λ£¨μ…˜μ„ λ³΄μ•˜μŠ΅λ‹ˆλ‹€. μ§€μ—°λœ μ œμ•½ 쑰건을 μ—†μ• κΈ° μœ„ν•΄ μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ½”λ“œλ₯Ό λ‹€μ‹œ μž‘μ„±ν•˜κ±°λ‚˜ pg_repack에 이λ₯Ό μ‚¬μš©ν•˜λ„λ‘ "κ°€λ₯΄μΉ˜λŠ”" κ²ƒμž…λ‹ˆλ‹€. μš°λ¦¬λŠ” 두 번째λ₯Ό μ„ νƒν–ˆμŠ΅λ‹ˆλ‹€.

μƒˆ ν…Œμ΄λΈ”μ˜ 인덱슀λ₯Ό μ›λž˜ ν…Œμ΄λΈ”μ˜ μ§€μ—°λœ μ œμ•½ 쑰건으둜 ꡐ체

κ°œμ •μ˜ λͺ©μ μ€ λΆ„λͺ…ν–ˆμŠ΅λ‹ˆλ‹€. 원본 ν…Œμ΄λΈ”μ— μ§€μ—°λœ μ œμ•½ 쑰건이 μžˆλŠ” 경우 μƒˆ ν…Œμ΄λΈ”μ— λŒ€ν•΄μ„œλŠ” μΈλ±μŠ€κ°€ μ•„λ‹Œ μ΄λŸ¬ν•œ μ œμ•½ 쑰건을 생성해야 ν•©λ‹ˆλ‹€.

λ³€κ²½ 사항을 ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•΄ κ°„λ‹¨ν•œ ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„±ν–ˆμŠ΅λ‹ˆλ‹€.

  • μ§€μ—°λœ μ œμ•½ 쑰건과 ν•˜λ‚˜μ˜ λ ˆμ½”λ“œκ°€ μžˆλŠ” ν…Œμ΄λΈ”;
  • κΈ°μ‘΄ λ ˆμ½”λ“œμ™€ μΆ©λŒν•˜λŠ” 루프에 데이터λ₯Ό μ‚½μž…ν•©λ‹ˆλ‹€.
  • μ—…λ°μ΄νŠΈλ₯Ό μˆ˜ν–‰ν•˜μ„Έμš”. 데이터가 더 이상 μΆ©λŒν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
  • λ³€κ²½ 사항을 μ»€λ°‹ν•©λ‹ˆλ‹€.

create table test_table
(
  id serial,
  val int,
  constraint uk_test_table__val unique (val) deferrable initially deferred 
);

INSERT INTO test_table (val) VALUES (0);
FOR i IN 1..10000 LOOP
  BEGIN
    INSERT INTO test_table VALUES (0) RETURNING id INTO v_id;
    UPDATE test_table set val = i where id = v_id;
    COMMIT;
  END;
END LOOP;

pg_repack의 원본 버전은 항상 첫 번째 μ‚½μž… μ‹œ 좩돌이 λ°œμƒν–ˆμœΌλ©° μˆ˜μ •λœ 버전은 였λ₯˜ 없이 μž‘λ™ν–ˆμŠ΅λ‹ˆλ‹€. μ—„μ²­λ‚œ.

ν”„λ‘œλ•μ…˜μœΌλ‘œ μ΄λ™ν•˜λ©΄ 둜그 ν…Œμ΄λΈ”μ—μ„œ μƒˆ ν…Œμ΄λΈ”λ‘œ 데이터λ₯Ό λ³΅μ‚¬ν•˜λŠ” 것과 λ™μΌν•œ λ‹¨κ³„μ—μ„œ λ‹€μ‹œ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

$ ./pg_repack -t tablename -o id
INFO: repacking table "tablename"
ERROR: query failed: 
    ERROR: duplicate key value violates unique constraint "index_16508"
DETAIL:  Key (id, index)=(100500, 42) already exists.

고전적인 상황: ν…ŒμŠ€νŠΈ ν™˜κ²½μ—μ„œλŠ” λͺ¨λ“  것이 μž‘λ™ν•˜μ§€λ§Œ ν”„λ‘œλ•μ…˜ ν™˜κ²½μ—μ„œλŠ” μž‘λ™ν•˜μ§€ μ•ŠμŠ΅λ‹ˆκΉŒ?!

APPLY_COUNT 및 두 배치의 ꡐ차점

μš°λ¦¬λŠ” μ½”λ“œλ₯Ό 문자 κ·ΈλŒ€λ‘œ ν•œ 쀄씩 λΆ„μ„ν•˜κΈ° μ‹œμž‘ν–ˆκ³  μ€‘μš”ν•œ 점을 λ°œκ²¬ν–ˆμŠ΅λ‹ˆλ‹€. λ°μ΄ν„°λŠ” 둜그 ν…Œμ΄λΈ”μ—μ„œ μƒˆ ν…Œμ΄λΈ”λ‘œ 배치둜 μ „μ†‘λ˜κ³  APPLY_COUNT μƒμˆ˜λŠ” 배치의 크기λ₯Ό λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

for (;;)
{
num = apply_log(connection, table, APPLY_COUNT);

if (num > MIN_TUPLES_BEFORE_SWITCH)
     continue;  /* there might be still some tuples, repeat. */
...
}

λ¬Έμ œλŠ” μ—¬λŸ¬ μž‘μ—…μ΄ 잠재적으둜 μ œμ•½ 쑰건을 μœ„λ°˜ν•  수 μžˆλŠ” μ›λž˜ νŠΈλžœμž­μ…˜μ˜ 데이터가 전솑될 λ•Œ 두 배치의 κ΅μ°¨μ μ—μ„œ 끝날 수 μžˆλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€. λͺ…λ Ήμ˜ μ ˆλ°˜μ€ 첫 번째 λ°°μΉ˜μ—μ„œ μ»€λ°‹λ˜κ³  λ‚˜λ¨Έμ§€ μ ˆλ°˜μ€ μ»€λ°‹λ©λ‹ˆλ‹€. 두 λ²ˆμ§Έμ—. 그리고 μ—¬κΈ°μ„œλŠ” μš΄μ— 따라 νŒ€μ΄ 첫 번째 λ°°μΉ˜μ—μ„œ 아무 것도 μœ„λ°˜ν•˜μ§€ μ•ŠμœΌλ©΄ λͺ¨λ“  것이 μ •μƒμ΄μ§€λ§Œ μœ„λ°˜ν•˜λ©΄ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€.

APPLY_COUNTλŠ” 1000개의 λ ˆμ½”λ“œμ™€ λ™μΌν•©λ‹ˆλ‹€. μ΄λŠ” ν…ŒμŠ€νŠΈκ°€ μ„±κ³΅ν•œ 이유λ₯Ό μ„€λͺ…ν•©λ‹ˆλ‹€. "배치 μ ‘ν•©"의 κ²½μš°λŠ” 닀루지 μ•Šμ•˜μŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” insert와 updateλΌλŠ” 두 가지 λͺ…령을 μ‚¬μš©ν–ˆκΈ° λ•Œλ¬Έμ— 두 λͺ…λ Ήμ˜ μ •ν™•νžˆ 500개의 νŠΈλžœμž­μ…˜μ΄ 항상 배치둜 λ°°μΉ˜λ˜μ—ˆμœΌλ©° μ•„λ¬΄λŸ° λ¬Έμ œλ„ λ°œμƒν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. 두 번째 μ—…λ°μ΄νŠΈλ₯Ό μΆ”κ°€ν•œ ν›„ νŽΈμ§‘ λ‚΄μš©μ΄ μž‘λ™μ„ λ©ˆμ·„μŠ΅λ‹ˆλ‹€.

FOR i IN 1..10000 LOOP
  BEGIN
    INSERT INTO test_table VALUES (1) RETURNING id INTO v_id;
    UPDATE test_table set val = i where id = v_id;
    UPDATE test_table set val = i where id = v_id; -- one more update
    COMMIT;
  END;
END LOOP;

λ”°λΌμ„œ λ‹€μŒ μž‘μ—…μ€ ν•œ νŠΈλžœμž­μ…˜μ—μ„œ λ³€κ²½λœ 원본 ν…Œμ΄λΈ”μ˜ 데이터가 μ—­μ‹œ ν•œ νŠΈλžœμž­μ…˜ λ‚΄μ—μ„œ μƒˆ ν…Œμ΄λΈ”μ— μžˆλŠ”μ§€ ν™•μΈν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

일괄 처리 κ±°λΆ€

그리고 μš°λ¦¬μ—κ²ŒλŠ” 두 가지 해결책이 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 첫째, 배치둜의 뢄할을 μ™„μ „νžˆ ν¬κΈ°ν•˜κ³  ν•˜λ‚˜μ˜ νŠΈλžœμž­μ…˜μœΌλ‘œ 데이터λ₯Ό μ „μ†‘ν•©μ‹œλ‹€. 이 μ†”λ£¨μ…˜μ˜ μž₯점은 λ‹¨μˆœμ„±μ΄μ—ˆμŠ΅λ‹ˆλ‹€. ν•„μš”ν•œ μ½”λ“œ 변경이 μ΅œμ†Œν™”λ˜μ—ˆμŠ΅λ‹ˆλ‹€(그런데 이전 λ²„μ „μ—μ„œλŠ” pg_reorgκ°€ μ •ν™•νžˆ κ·Έλ ‡κ²Œ μž‘λ™ν–ˆμŠ΅λ‹ˆλ‹€). κ·ΈλŸ¬λ‚˜ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” μž₯κΈ° 거래λ₯Ό μƒμ„±ν•˜κ³  있으며 μ΄λŠ” 이전에 λ§ν–ˆλ“―μ΄ μƒˆλ‘œμš΄ 팽창의 μΆœν˜„μ— λŒ€ν•œ μœ„ν˜‘μž…λ‹ˆλ‹€.

두 번째 ν•΄κ²° 방법은 더 λ³΅μž‘ν•˜μ§€λ§Œ μ•„λ§ˆλ„ 더 μ •ν™•ν•  κ²ƒμž…λ‹ˆλ‹€. 즉, ν…Œμ΄λΈ”μ— 데이터λ₯Ό μΆ”κ°€ν•œ νŠΈλžœμž­μ…˜μ˜ μ‹λ³„μžλ₯Ό μ‚¬μš©ν•˜μ—¬ 둜그 ν…Œμ΄λΈ”μ— 열을 μƒμ„±ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€. 그런 λ‹€μŒ 데이터λ₯Ό 볡사할 λ•Œ 이 μ†μ„±λ³„λ‘œ κ·Έλ£Ήν™”ν•˜κ³  κ΄€λ ¨ λ³€κ²½ 사항이 ν•¨κ»˜ μ „μ†‘λ˜λ„λ‘ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ°°μΉ˜λŠ” μ—¬λŸ¬ νŠΈλžœμž­μ…˜(λ˜λŠ” ν•˜λ‚˜μ˜ 큰 νŠΈλžœμž­μ…˜)으둜 κ΅¬μ„±λ˜λ©° ν•΄λ‹Ή νŠΈλžœμž­μ…˜μ—μ„œ λ³€κ²½λœ λ°μ΄ν„°μ˜ 양에 따라 크기가 λ‹¬λΌμ§‘λ‹ˆλ‹€. μ„œλ‘œ λ‹€λ₯Έ νŠΈλžœμž­μ…˜μ˜ 데이터가 λ¬΄μž‘μœ„ μˆœμ„œλ‘œ 둜그 ν…Œμ΄λΈ”μ— μž…λ ₯λ˜λ―€λ‘œ 더 이상 μ΄μ „μ²˜λŸΌ 순차적으둜 읽을 수 μ—†κ²Œ λœλ‹€λŠ” 점에 μœ μ˜ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€. tx_id둜 ν•„ν„°λ§ν•˜λŠ” 각 μš”μ²­μ— λŒ€ν•œ seqscan은 λΉ„μš©μ΄ λ„ˆλ¬΄ 많이 λ“€κ³  μΈλ±μŠ€κ°€ ν•„μš”ν•˜μ§€λ§Œ μ—…λ°μ΄νŠΈ μ˜€λ²„ν—€λ“œλ‘œ 인해 방법 속도가 λŠλ €μ§‘λ‹ˆλ‹€. 일반적으둜 항상 그렇듯이 무언가λ₯Ό 희생해야 ν•©λ‹ˆλ‹€.

κ·Έλž˜μ„œ μš°λ¦¬λŠ” 더 κ°„λ‹¨ν•œ 첫 번째 μ˜΅μ…˜λΆ€ν„° μ‹œμž‘ν•˜κΈ°λ‘œ κ²°μ •ν–ˆμŠ΅λ‹ˆλ‹€. 첫째, κΈ΄ κ±°λž˜κ°€ μ‹€μ œλ‘œ λ¬Έμ œκ°€ 될지 μ΄ν•΄ν•˜λŠ” 것이 ν•„μš”ν–ˆμŠ΅λ‹ˆλ‹€. 이전 ν…Œμ΄λΈ”μ—μ„œ μƒˆ ν…Œμ΄λΈ”λ‘œμ˜ μ£Όμš” 데이터 전솑도 ν•˜λ‚˜μ˜ κΈ΄ νŠΈλžœμž­μ…˜μ—μ„œ λ°œμƒν•˜λ―€λ‘œ μ§ˆλ¬Έμ€ "이 νŠΈλžœμž­μ…˜μ„ μ–Όλ§ˆλ‚˜ 늘릴 것인가?"둜 μ „ν™˜λ©λ‹ˆλ‹€. 첫 번째 νŠΈλžœμž­μ…˜μ˜ 기간은 주둜 ν…Œμ΄λΈ” 크기에 따라 λ‹¬λΌμ§‘λ‹ˆλ‹€. μƒˆλ‘œμš΄ 기간은 데이터 전솑 쀑에 ν…Œμ΄λΈ”μ— λˆ„μ λœ λ³€κ²½ 사항 μˆ˜μ— 따라 λ‹¬λΌμ§‘λ‹ˆλ‹€. ν•˜μ€‘μ˜ 강도에 따라. pg_repack 싀행은 μ„œλΉ„μŠ€ λ‘œλ“œκ°€ μ΅œμ†ŒμΈ μ‹œκ°„μ— λ°œμƒν–ˆμœΌλ©° ν…Œμ΄λΈ”μ˜ μ›λž˜ 크기에 λΉ„ν•΄ λ³€κ²½λŸ‰μ΄ λ„ˆλ¬΄ μž‘μ•˜μŠ΅λ‹ˆλ‹€. μš°λ¦¬λŠ” μƒˆλ‘œμš΄ 거래 μ‹œκ°„μ„ λ¬΄μ‹œν•  수 μžˆλ‹€κ³  κ²°μ •ν–ˆμŠ΅λ‹ˆλ‹€(비ꡐλ₯Ό μœ„ν•΄ 평균 1μ‹œκ°„ 2~3λΆ„μž…λ‹ˆλ‹€).

μ‹€ν—˜μ€ κΈμ •μ μ΄μ—ˆμŠ΅λ‹ˆλ‹€. 생산도 μ‹œμž‘ν•˜μ„Έμš”. λͺ…확성을 μœ„ν•΄ λ‹€μŒμ€ μ‹€ν–‰ ν›„ λ°μ΄ν„°λ² μ΄μŠ€ 쀑 ν•˜λ‚˜μ˜ 크기λ₯Ό λ³΄μ—¬μ£ΌλŠ” κ·Έλ¦Όμž…λ‹ˆλ‹€.

Postgres: 팽창, pg_repack 및 지연 μ œμ•½ 쑰건

μš°λ¦¬λŠ” 이 μ†”λ£¨μ…˜μ— μ™„μ „νžˆ λ§Œμ‘±ν–ˆκΈ° λ•Œλ¬Έμ— 두 번째 μ†”λ£¨μ…˜μ„ κ΅¬ν˜„ν•˜λ €κ³  μ‹œλ„ν•˜μ§€λŠ” μ•Šμ•˜μ§€λ§Œ ν™•μž₯ κ°œλ°œμžμ™€ λ…Όμ˜ν•  κ°€λŠ₯성을 κ³ λ €ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. λΆˆν–‰ν•˜κ²Œλ„ 우리의 ν˜„μž¬ κ°œμ •νŒμ€ 아직 κ²Œμ‹œν•  μ€€λΉ„κ°€ λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. μ™œλƒν•˜λ©΄ μš°λ¦¬λŠ” κ³ μœ ν•œ μ§€μ—°λœ μ œν•œ μ‚¬ν•­μœΌλ‘œλ§Œ 문제λ₯Ό ν•΄κ²°ν–ˆκ³  μ™„μ „ν•œ 패치λ₯Ό μœ„ν•΄μ„œλŠ” λ‹€λ₯Έ μœ ν˜•μ— λŒ€ν•œ 지원을 μ œκ³΅ν•΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. μš°λ¦¬λŠ” λ―Έλž˜μ—λ„ 이것을 ν•  수 있기λ₯Ό λ°”λžλ‹ˆλ‹€.

μ•„λ§ˆλ„ 당신은 질문이 μžˆμ„ κ²ƒμž…λ‹ˆλ‹€. μ™œ μš°λ¦¬λŠ” pg_repack을 μˆ˜μ •ν•˜μ—¬ 이 이야기에 μ°Έμ—¬ν•˜κ³  예λ₯Ό λ“€μ–΄ κ·Έ μœ μ‚¬μ²΄λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆκΉŒ? μ–΄λŠ μ‹œμ μ—μ„œ μš°λ¦¬λ„ 이것에 λŒ€ν•΄ μƒκ°ν–ˆμ§€λ§Œ, μ§€μ—°λœ μ œμ•½ 쑰건이 μ—†λŠ” ν…Œμ΄λΈ”μ—μ„œ 더 일찍 그것을 μ‚¬μš©ν•œ 긍정적인 κ²½ν—˜μ€ μš°λ¦¬κ°€ 문제의 λ³Έμ§ˆμ„ μ΄ν•΄ν•˜κ³  ν•΄κ²°ν•˜λ €κ³  λ…Έλ ₯ν•˜λ„λ‘ 동기λ₯Ό λΆ€μ—¬ν–ˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ λ‹€λ₯Έ μ†”λ£¨μ…˜μ„ μ‚¬μš©ν•˜λŠ” κ²½μš°μ—λ„ ν…ŒμŠ€νŠΈλ₯Ό μˆ˜ν–‰ν•˜λŠ” 데 μ‹œκ°„μ΄ ν•„μš”ν•˜λ―€λ‘œ λ¨Όμ € 문제λ₯Ό ν•΄κ²°ν•˜λ €κ³  λ…Έλ ₯ν•˜κ³  합리적인 μ‹œκ°„ 내에 이λ₯Ό μˆ˜ν–‰ν•  수 μ—†λ‹€λŠ” 것을 κΉ¨λ‹«κ²Œ 되면 μœ μ‚¬μ μ„ μ‚΄νŽ΄λ³΄κΈ° μ‹œμž‘ν–ˆμŠ΅λ‹ˆλ‹€. .

쑰사 κ²°κ³Ό

우리의 κ²½ν—˜μ„ λ°”νƒ•μœΌλ‘œ μš°λ¦¬κ°€ μΆ”μ²œν•  수 μžˆλŠ” 것:

  1. λ‹Ήμ‹ μ˜ λΆ€ν’€μ–΄ 였λ₯Έ 뢀뢄을 λͺ¨λ‹ˆν„°λ§ν•˜μ‹­μ‹œμ˜€. λͺ¨λ‹ˆν„°λ§ 데이터λ₯Ό 톡해 autovacuum이 μ–Όλ§ˆλ‚˜ 잘 κ΅¬μ„±λ˜μ–΄ μžˆλŠ”μ§€ 이해할 수 μžˆμŠ΅λ‹ˆλ‹€.
  2. νŒ½μ°½μ„ ν—ˆμš© κ°€λŠ₯ν•œ μˆ˜μ€€μœΌλ‘œ μœ μ§€ν•˜λ €λ©΄ AUTOVACUUM을 μ‘°μ •ν•˜μ„Έμš”.
  3. λΆ€ν’€μ–΄μ˜€λ₯΄λŠ” 뢀뢄이 μ—¬μ „νžˆ 컀지고 κΈ°λ³Έ 도ꡬλ₯Ό μ‚¬μš©ν•˜μ—¬ 이λ₯Ό 극볡할 수 μ—†λŠ” 경우 μ™ΈλΆ€ ν™•μž₯ κΈ°λŠ₯을 μ‚¬μš©ν•˜λŠ” 것을 λ‘λ €μ›Œν•˜μ§€ λ§ˆμ‹­μ‹œμ˜€. κ°€μž₯ μ€‘μš”ν•œ 것은 λͺ¨λ“  것을 잘 ν…ŒμŠ€νŠΈν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
  4. ν•„μš”μ— 맞게 μ™ΈλΆ€ μ†”λ£¨μ…˜μ„ μˆ˜μ •ν•˜λŠ” 것을 λ‘λ €μ›Œν•˜μ§€ λ§ˆμ„Έμš”. λ•Œλ‘œλŠ” μžμ‹ μ˜ μ½”λ“œλ₯Ό λ³€κ²½ν•˜λŠ” 것보닀 이것이 더 효과적이고 더 μ‰¬μšΈ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

좜처 : habr.com

μ½”λ©˜νŠΈλ₯Ό μΆ”κ°€