DB μ‹€ν–‰κ³„νš 확인법(in PostgreSQL)

2023. 11. 11. 19:32ㆍDatabase/DB μŠ€ν„°λ””

일반적인 μ„œλ²„ - ν΄λΌμ΄μ–ΈνŠΈ λͺ¨λΈμ—μ„œ μ„œλ²„ 츑은 λ°μ΄ν„°μ˜ μ˜μ†μ„±μ„ μœ„ν•΄ Databaseλ₯Ό ν™œμš©ν•œλ‹€. 

μ΄λŸ¬ν•œ μƒν™©μ—μ„œ λ°μ΄ν„°μ˜ 흐름은 κ°„λž΅ν•˜κ²Œ ν‘œν˜„ν•˜λ©΄ ν΄λΌμ΄μ–ΈνŠΈ - WAS - DB 의 ν˜•νƒœκ°€ λ˜λŠ”λ°, 일반적인 RDB κΈ°μ€€ 데이터듀은 λͺ¨λ‘ Disk에 적재되기 λ•Œλ¬Έμ— μ‹œμŠ€ν…œ μ½œμ„ μœ λ°œν•˜κ²Œ 되고 μ„œλ²„ ν™˜κ²½ λ‚΄ 병λͺ©μ΄ κ°€μž₯ 많이 λ°œμƒν•˜λŠ” 지점 쀑 ν•˜λ‚˜κ°€ λœλ‹€.

κ²°κ΅­ WAS - DB κ°„ 응닡 μ†λ„μ˜ κ°œμ„ μ΄ 전체 응닡 μ†λ„μ˜ κ°œμ„ μœΌλ‘œ μ΄μ–΄μ§€λŠ” κ²½μš°κ°€ 많기 λ•Œλ¬Έμ— 쿼리의 κ°œμ„ μ„ μ΄λ£¨μ–΄λ‚΄λŠ” 것은 λͺΉμ‹œ μ€‘μš”ν•˜λ‹€.

μ—¬κΈ°κΉŒμ§€ μ˜€κ³ λ‚˜λ©΄ κ°œμ„ μ΄ μ€‘μš”ν•˜λ‹€λŠ” 것은 이해가 λ˜λŠ”λ°, 쿼리 μˆ˜μ •μ„ 톡해 κ°œμ„ μ΄ 이루어지고 μžˆλŠ”μ§€ νŒλ‹¨ν•˜λŠ” 기쀀은 λ¬΄μ—‡μœΌλ‘œ μ‚Όμ•„μ•Όν• κΉŒ?

λ¬Όλ‘  ν΄λΌμ΄μ–ΈνŠΈ μΈ‘μ—μ„œ 개발자 도ꡬλ₯Ό 톡해 응닡 속도가 μ–΄λ–»κ²Œ λ³€ν™”ν•˜λŠ”μ§€ 확인해봐도 되고, ν˜Ήμ€ μ„œλ²„ μΈ‘μ—μ„œ DB의 응닡 μ‹œκ°„μ„ 직접 츑정해봐도 λ˜μ§€λ§Œ μ—¬κΈ°μ—μ„œλŠ” κ·Έλ³΄λ‹€λŠ” 더 μ‹€μ „μ—μ„œ ν™œμš©ν•  수 μžˆλŠ” μ‹€ν–‰ κ³„νšμ— λŒ€ν•΄ κ°„λ‹¨νžˆ 닀루렀고 ν•œλ‹€.

 

λ“€μ–΄κ°€κΈ° μ•žμ„œ

ν•΄λ‹Ή λ¬Έμ„œμ˜ μ˜ˆμ‹œλ“€μ€ λͺ¨λ‘ μ•„λž˜μ˜ ν…Œμ΄λΈ” 상황을 κ°€μ •ν•˜κ³  μž‘μ„±

각 ν…Œμ΄λΈ”λ“€μ€ λͺ¨λ‘ 더미 데이터가 포함

μ˜ˆμ‹œ ν…Œμ΄λΈ” ERD

  • Company
    • idx: id
    • rows: 200
  • Item
    • idx: id
    • rows: 2000
  • User
    • idx: id
    • rows: 10000
  • Purchase
    • idx: id
    • rows: 500000

 

μ‹€ν–‰ κ³„νš 쿼리 μž‘μ„±λ²•

μ‹€ν–‰ κ³„νšμ˜ 확인은 크게 EXPLAIN λ¬Έκ³Ό EXPLAIN ANALYZE 문으둜 λ‚˜λ‰œλ‹€.

μ „μžμ˜ κ²½μš°μ—” νŠΉμ • 쿼리에 λŒ€ν•΄ DBκ°€ μ˜ˆμƒν•œ κ²°κ³Όλ₯Ό 좜λ ₯ν•˜λ©°, ν›„μžλŠ” μ˜ˆμƒκ³Ό λ”λΆˆμ–΄ μ‹€μ œ 쿼리λ₯Ό μ‹€ν–‰μ‹œμΌœ λ³Έ κ²°κ³ΌκΉŒμ§€ 좜λ ₯ν•œλ‹€.

ν•΄λ‹Ή λ¬Έμ„œμ—μ„œλŠ” ν›„μž(EXPLAIN ANALYZE) λ§Œμ„ λ‹€λ£¨κ² μŒ.

싀행법

EXPLAIN (ANALYZE, VERBOSE, BUFFERS, TIMING) (
  -- ν™•μΈν•˜κΈ° μœ„ν•œ 쿼리
  SELECT * FROM purchase WHERE count > 5;
)

κ²°κ³Ό

ꡬ맀 이λ ₯ ν…Œμ΄λΈ”μ—μ„œ ν•œλ²ˆμ— κ΅¬λ§€ν•œ λ¬Όν’ˆμ˜ μˆ˜κ°€ 5κ°œκ°€ λ„˜λŠ” ꡬ맀 이λ ₯λ§Œμ„ μ‘°νšŒν•˜λŠ” 쿼리의 μ‹€ν–‰ κ³„νšμ„ 좜λ ₯

 

μ‹€ν–‰ κ³„νš 해석

μ½λŠ” 법

λ…Έλ“œμ— 각각 μ–΄λ–€ λ‚΄μš©μ΄ λ“€μ–΄κ°€λŠ”μ§€ ν™•μΈν•˜κΈ° μ•žμ„œ, μ‹€ν–‰ κ³„νšμ„ μ½λŠ” 방법은 μ•„λž˜μ™€ κ°™λ‹€.

  1. μ‹€ν–‰ κ³„νšμ€ 각 μž‘μ—…μ„ λ…Έλ“œλ‘œ ν‘œν˜„ν•œ κ·Έλž˜ν”„ ν˜•νƒœλ‘œ λ‚˜νƒ€λ‚˜λ©°, νŠΉμ • λ…Έλ“œλŠ” ν•˜μœ„ λ…Έλ“œλ₯Ό 포함할 수 있고 λ…Έλ“œ κ°„ λŽμŠ€λŠ” ν™”μ‚΄ν‘œλ‘œ ν‘œν˜„λœλ‹€.
  2. 같은 뎁슀의 μž‘μ—… κ°„μ—λŠ” μœ„μ—μ„œλΆ€ν„° μ‹€ν–‰λ˜κ³ , λŽμŠ€κ°€ λ‹€λ₯Ό κ²½μš°μ—” 더 κΉŠμ€ λ…Έλ“œμ˜ μž‘μ—…μ΄ λ¨Όμ € μ‹€ν–‰λœλ‹€.
  3. 각 λ…Έλ“œ ν•˜μœ„μ—λŠ” ν•΄λ‹Ή μž‘μ—…μ— λŒ€ν•œ 좔가적인 μ„€λͺ…이 ν¬ν•¨λœλ‹€. (μœ„ μ˜ˆμ‹œ κΈ°μ€€ Output, Filter λ“±)

λ…Έλ“œ ꡬ성 μš”μ†Œ

μ‹€ν–‰ κ³„νšμ˜ 각 λ…Έλ“œμ—λŠ” μ•„λž˜μ˜ μš”μ†Œλ“€μ΄ ν¬ν•¨λ˜μ–΄ μžˆλ‹€.

  • λΉ„μš©(Cost)
    • λ”°λ‘œ λ‹¨μœ„κ°€ μ—†λŠ” 좔상적인 κ°’μ΄μ§€λ§Œ, 일반적으둜 데이터λ₯Ό κ°€μ Έμ˜€λŠ”λ° ν•„μš”ν•œ Disk I/O의 λΉˆλ„μ™€ κ·Έ μ™Έ μ‚¬μš©λ˜λŠ” μ»΄ν“¨νŒ… λ¦¬μ†ŒμŠ€λ₯Ό μ’…ν•©ν•œ κ°’
    • μ»΄ν“¨νŒ… λ¦¬μ†ŒμŠ€λ₯Ό 총제적으둜 ν•¨μΆ•ν•˜κ³  있기 λ•Œλ¬Έμ— 쿼리 μ‹€ν–‰ μ‹œκ°„κ³Ό μ •λΉ„λ‘€ν•˜μ§€λŠ” μ•Šμ§€λ§Œ, 쿼리 μ‹€ν–‰μ—μ„œ Disk I/Oκ°€ μ°¨μ§€ν•˜λŠ” 비쀑이 ν¬λ‹€λ³΄λ‹ˆ μ–΄λŠμ •λ„μ˜ κ²½ν–₯성은 쑴재
    • 2개의 값이 λ°˜ν™˜λ˜λ©°, ν•˜λ‚˜λŠ” 쑰건에 λ§žλŠ” 첫번째 rowλ₯Ό 찾을 λ•ŒκΉŒμ§€ κ±Έλ¦¬λŠ” λΉ„μš©μ΄κ³  λ‹€λ₯Έ ν•˜λ‚˜λŠ” 쑰건을 λ§Œμ‘±ν•˜λŠ” λͺ¨λ“  데이터λ₯Ό 찾을 λ•ŒκΉŒμ§€ κ±Έλ¦¬λŠ” λΉ„μš©
  • 둜우(Rows)
    • νŠΉμ • λ…Έλ“œμ˜ 결과둜 λ°˜ν™˜λœ 데이터(row)의 수
  • 폭(width)
    • νŠΉμ • λ…Έλ“œμ˜ 결과둜 λ°˜ν™˜λœ λ°μ΄ν„°μ˜ 평균 width κ°’(λ‹¨μœ„: λ°”μ΄νŠΈ)
  • 버퍼(Buffers)
    • Buffers μ˜΅μ…˜μ„ 켰을 λ•Œλ§Œ λ‚˜νƒ€λ‚˜λŠ” κ°’
    • ν¬κ²ŒλŠ” hitκ³Ό readκ°€ μ‘΄μž¬ν•˜λŠ”λ°, hit은 버퍼 μΊμ‹œμ—μ„œ μ½μ–΄μ˜¨ λΈ”λ‘μ˜ 수이고 readλŠ” Disk IOλ₯Ό 톡해 μΌκ²…μ˜¨ λΈ”λ‘μ˜ 수(블둝 = 일반적으둜 8kb, DB의 λͺ¨λ“  IOλŠ” 블둝 λ‹¨μœ„λ‘œ 행해짐)
  • λ…Έλ“œ νƒ€μž…
    • Seq Scan : ν…Œμ΄λΈ” Full Scan
    • Index Scan : 인덱슀λ₯Ό ν™œμš©ν•œ ν…Œμ΄λΈ” μŠ€μΊ”
    • Index Only Scan : μΏΌλ¦¬μ—μ„œ μš”κ΅¬λ˜λŠ” λͺ¨λ“  데이터가 μΈλ±μŠ€μ— μ „λΆ€ μ‘΄μž¬ν•˜μ—¬ 인덱슀만 μŠ€μΊ”
    • Nested Loop Join : ν…Œμ΄λΈ”μ„ NL 쑰인 ν˜•μ‹μœΌλ‘œ 톡합
    • Hash Join : ν…Œμ΄λΈ”μ„ ν•΄μ‹œ 쑰인 ν˜•μ‹μœΌλ‘œ 톡합
    • Sort : ν…Œμ΄λΈ” μ •λ ¬ μˆ˜ν–‰
    • Aggregate : 집계 ν•¨μˆ˜λ₯Ό 톡해 데이터 톡합

 

λ‹€μ–‘ν•œ 쿼리 μ˜ˆμ‹œ

1. 인덱슀 필터링 예제

쿼리

SELECT * 
FROM item
WHERE id > 21800
ORDER BY id ASC

κ²°κ³Ό

해석

  • item ν…Œμ΄λΈ”μ—μ„œ idκ°€ 21800보닀 큰 λ°μ΄ν„°λ§Œμ„ μ‘°νšŒν•˜κ³  이λ₯Ό id 순으둜 μ •λ ¬ν•˜λŠ” 쿼리
  • idκ°€ 인덱슀둜 μ„€μ •λ˜μ–΄ 있기 λ•Œλ¬Έμ— Index Scan이 μˆ˜ν–‰. 이 λ•Œ κ²°κ³Ό rows μˆ˜κ°€ 200 뿐이기 λ•Œλ¬Έμ— Index Scan이 μ‹€ν–‰λ˜μ—ˆλ‹€κ³  λ³΄λŠ” 것이 맞고 인덱슀λ₯Ό 톡해 μ°Ύκ³ μžν•˜λŠ” λ²”μœ„κ°€ 더 넓을 κ²½μš°μ—” λ‹¨μˆœ ν…Œμ΄λΈ” ν’€μŠ€μΊ”μœΌλ‘œ μˆ˜ν–‰λ  κ°€λŠ₯성도 쑴재
  • ORDER BY 절이 μžˆμŒμ—λ„ SORT λ…Έλ“œκ°€ λ‚˜νƒ€λ‚˜μ§€ μ•Šμ•˜λŠ”λ°, μ΄λŠ” 이미 μ •λ ¬λœ 인덱슀λ₯Ό κΈ°μ€€μœΌλ‘œ 정렬을 μš”μ²­ν•˜μ˜€κΈ° λ•Œλ¬Έμ— μƒλž΅ κ°€λŠ₯

2. 쑰인 예제

쿼리

SELECT * 
FROM public.purchase p, public.user u
WHERE u.id = p.user_id AND u.avg_income > 80000000

κ²°κ³Ό

해석

  • μ—°κ°„ ν‰κ· μ†Œλ“μ΄ 8000λ§Œμ›μ΄ λ„˜λŠ” 고객의 데이터와 ꡬ맀 λͺ©λ‘μ„ ν™•μΈν•˜λŠ” 쿼리
  • user ν…Œμ΄λΈ”μ—μ„œ μ—°κ°„ ν‰κ· μ†Œλ“ 쑰건을 λ§Œμ‘±ν•˜λŠ” 데이터λ₯Ό ν…Œμ΄λΈ” ν’€μŠ€μΊ” 방식을 톡해 확인
  • ν•„ν„°λ§λœ user 데이터λ₯Ό 톡해 쑰인 κΈ°μ€€ 칼럼인 user.id 값을 ν‚€λ‘œ κ°–λŠ” ν•΄μ‹œν…Œμ΄λΈ” 생성
  • purchase ν…Œμ΄λΈ”μ—μ„œ user_id 칼럼이 ν•΄μ‹œν…Œμ΄λΈ”μ˜ ν‚€ κ°’μœΌλ‘œ μ‘΄μž¬ν•˜λŠ” 데이터듀을 ν’€μŠ€μΊ” ν˜•μ‹μœΌλ‘œ νšλ“
  • λ“œλΌμ΄λΉ™ ν…Œμ΄λΈ”μ˜ ν•„ν„°λ§λœ κ²°κ³Όκ°€ 더 μ μ—ˆλ‹€λ©΄ NL 쑰인을 μ„ νƒν–ˆμ„ κ°€λŠ₯μ„± UP

3. 톡계 예제

쿼리

SELECT u.id AS user_id, SUM(i.price * p.count) AS total_spent
FROM 
	public.purchase p, 
	public.item i,
	(
		SELECT id
		FROM public.user
		ORDER BY avg_income DESC 
		LIMIT 10
	) u
WHERE u.id = p.user_id AND i.id = p.item_id AND p.created_at BETWEEN NOW() - interval '1 month' AND NOW()
GROUP BY u.id

κ²°κ³Ό

해석

  • μ—°κ°„ μˆ˜μž…μ΄ κ°€μž₯ 높은 μ—΄λͺ…μ˜ μœ μ €μ˜ μ§€λ‚œ ν•œλ‹¬ κ°„ μ‚¬μš© κΈˆμ•‘ 톡계
  • user ν…Œμ΄λΈ”μ„ ν’€μŠ€μΊ”ν•˜μ—¬ ν•„μš”ν•œ 데이터λ₯Ό κ°€μ Έμ˜¨ λ’€ 이λ₯Ό 톡해 μ†Œλ“ 순으둜 μƒμœ„ 10개의 데이터λ₯Ό μ»·νŒ…ν•˜κ³  이λ₯Ό μž„μ‹œ ν…Œμ΄λΈ” u둜 μ‚¬μš©
  • u의 데이터λ₯Ό 틍해 idλ₯Ό κΈ°μ€€μœΌλ‘œ ν•΄μ‹œ ν…Œμ΄λΈ” 생성
  • ν•΄μ‹œ ν…Œμ΄λΈ”μ„ μ΄μš©ν•˜μ—¬ u와 purchase ν…Œμ΄λΈ” 쑰인
  • item ν…Œμ΄λΈ” λ‚΄μ—μ„œ 이전 μž‘μ—…μ„ 톡해 쑰인된 ν…Œμ΄λΈ”μ˜ item_id 값을 μ΄μš©ν•œ 인덱슀 μŠ€μΊ” μž‘μ—… μˆ˜ν–‰
  • ν•œλ²ˆ ν•΄μ‹œ 쑰인을 μˆ˜ν–‰ν•œ ν…Œμ΄λΈ”κ³Ό item ν…Œμ΄λΈ”μ—μ„œ 인덱슀 μŠ€μΊ”μ„ 톡해 νšλ“ν•œ 데이터 κ°„μ˜ NL 쑰인
  • u.idλ₯Ό κΈ°μ€€μœΌλ‘œ κ·Έλ£Ήν™” ν•˜κΈ° μœ„ν•œ μ†ŒνŒ… μˆ˜ν–‰
  • μ†ŒνŒ… κ²°κ³Όλ₯Ό λ°”νƒ•μœΌλ‘œ 톡계 κ°’ μ΅œμ’… 생성