๐Ÿ’ป ๊ฐœ๋ฐœ/๐Ÿ’พ Database

์ฝ˜์„œํŠธ ์˜ˆ์•ฝ ์„œ๋น„์Šค์˜ ์ธ๋ฑ์Šค ์„ค๊ณ„์™€ ์„ฑ๋Šฅ ๋น„๊ต

EastShine_ 2024. 11. 14. 15:31

 

๋“ค์–ด๊ฐ€๋ฉฐ

 ์ด๋ฒˆ ๊ธ€์—์„œ ์ฝ˜์„œํŠธ ์˜ˆ์•ฝ ์„œ๋น„์Šค์˜ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์‚ฌ์šฉ๋œ ์ฟผ๋ฆฌ๋ฅผ ๋ถ„์„ํ•˜๊ณ , ์ธ๋ฑ์Šค ์ถ”๊ฐ€ ์ „ํ›„์˜ ์„ฑ๋Šฅ์„ ๋น„๊ตํ•ด ๋ณด๋ฉฐ ์ตœ์ ํ™” ๊ณผ์ •์„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. MariaDB๋ฅผ ์‚ฌ์šฉํ•ด ์ธ๋ฑ์Šค ์ถ”๊ฐ€ ์ „ํ›„์˜ ์‹คํ–‰ ๊ณ„ํš(EXPLAIN) ๋ฐ ์ˆ˜ํ–‰ ์†๋„๋ฅผ ๋น„๊ตํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ด, ์ฟผ๋ฆฌ์˜ ์„ฑ๋Šฅ์„ ์ตœ์ข…์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๊ฐœ์„ ํ•˜์˜€๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

 

์‹œ๋‚˜๋ฆฌ์˜ค ๋‚ด ์ฟผ๋ฆฌ

๋จผ์ € ์ฝ˜์„œํŠธ ์˜ˆ์•ฝ ์„œ๋น„์Šค์˜ ๋„๋ฉ”์ธ ๋ณ„ ๊ฐ JpaRepository์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ๋ชจ๋‘ ์ˆ˜์ง‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋„๋ฉ”์ธ ๋ณ„ ์ฟผ๋ฆฌ๋ฅผ ์•„๋ž˜ ํ‘œ๋กœ ์ •๋ฆฌํ•ด๋ดค์Šต๋‹ˆ๋‹ค.

 

๋„๋ฉ”์ธ ๋ฉ”์„œ๋“œ
Concert findAllByConcertId()
Reservation findByIdOrNullWithLock(), findAllByExpiresAtBeforeAndStatus()
Seat findByIdOrNullWithLock(), findAllByScheduleId(), countUnavailableSeatsGroupByScheduleId()
Payment findAllByUserId()
BalanceHistory findAllByUserId()

 

 

 

์ž์ฃผ ์กฐํšŒํ•˜๊ฑฐ๋‚˜ ๋ณต์žกํ•œ ์ฟผ๋ฆฌ

์œ„ ์ฟผ๋ฆฌ ์ค‘ ์„ฑ๋Šฅ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ์ฟผ๋ฆฌ๋ฅผ ์‹๋ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

  1. ์ฝ˜์„œํŠธ ์ขŒ์„ ๋„๋ฉ”์ธ์˜ findAllByScheduleId() , ์ฝ˜์„œํŠธ ๋„๋ฉ”์ธ์˜ findAllByConcertId()
    • ํŠน์ • ID๋ฅผ ๊ฐ€์ง„ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์ฝ˜์„œํŠธ ์ขŒ์„ ๋„๋ฉ”์ธ์˜ countUnavailableSeatsGroupByScheduleId()
    • ๊ทธ๋ฃนํ™”์™€ COUNT ์—ฐ์‚ฐ์„ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  3. ์˜ˆ์•ฝ ๋„๋ฉ”์ธ์˜ findAllByExpiresAtBeforeAndStatus()
    • ๋‚ ์งœ ๋ฒ”์œ„์™€ ์ƒํƒœ ์กฐ๊ฑด์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

์ธ๋ฑ์Šค ์„ค๊ณ„ ๊ณผ์ • ๋ฐ ์„ฑ๋Šฅ ์ธก์ •

DB๋Š” MariaDB๋ฅผ ์‚ฌ์šฉํ–ˆ๊ณ  10.6.4 ๋ฒ„์ „์„ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

์‹ค์ œ ์ฝ˜์„œํŠธ ์˜ˆ์•ฝ ์‹œ์Šคํ…œ์—์„œ ์ฝ˜์„œํŠธ๊ฐ€ ์ขŒ์„ 5๋งŒ ์„์— ๋‹ฌํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ, ์ด๋ฒˆ ํ…Œ์ŠคํŠธ์—์„œ๋Š” ์ฝ˜์„œํŠธ ์Šค์ผ€์ค„ 20๊ฐœ๋งˆ๋‹ค 5๋งŒ ๊ฐœ์˜ ์ขŒ์„์„ ์‚ฝ์ž…ํ•˜์—ฌ ์ด ๋ฐฑ๋งŒ ๊ฐœ์˜ ์ขŒ์„ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‹ค์ œ์™€ ๋น„์Šทํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋ชจ์‚ฌํ•˜๊ณ , ์œ„์—์„œ ์„ ์ •ํ•œ 3๊ฐœ์˜ ์ฟผ๋ฆฌ์— ๋Œ€ํ•ด ์ธ๋ฑ์Šค ์„ค๊ณ„ ๋ฐ ์„ฑ๋Šฅ ๋น„๊ต๋ฅผ ์ธก์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

 

1. Seat ํ…Œ์ด๋ธ”์˜ findAllByScheduleId()

select *
from seat
where schedule_id = 7;

์œ„์™€ ๊ฐ™์ด ์ขŒ์„์„ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ์— ๋Œ€ํ•ด  schedule_id๋กœ ์ธ๋ฑ์‹ฑ ์ „ํ›„ ์‹คํ–‰ ๊ณ„ํš๊ณผ ์„ฑ๋Šฅ์„ ๋น„๊ตํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

 

 

์ธ๋ฑ์‹ฑ ์ „

Explain ๊ฒฐ๊ณผ
์ฟผ๋ฆฌ ์ˆ˜ํ–‰ ์‹œ๊ฐ„

 

ํ•ด๋‹น ์ฟผ๋ฆฌ์˜ ์‹คํ–‰ ๊ณ„ํš์„ ๋ณด๋ฉด ALL ์Šค์บ”์ด ์ด๋ฃจ์–ด์กŒ์œผ๋ฉฐ, ์‹คํ–‰ ์†๋„๋Š” 352ms์˜€์Šต๋‹ˆ๋‹ค.

 

 

 

์ธ๋ฑ์‹ฑ ํ›„

CREATE INDEX idx_schedule_id ON seat(schedule_id);

 

Explain ๊ฒฐ๊ณผ
์ฟผ๋ฆฌ ์ˆ˜ํ–‰ ์‹œ๊ฐ„

 

schedule_id ์ปฌ๋Ÿผ์— ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•œ ํ›„์—๋Š” ref ์Šค์บ”์œผ๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์œผ๋ฉฐ, ์‹คํ–‰ ์†๋„๋Š” 65ms๋กœ ํฌ๊ฒŒ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

2. Seat ํ…Œ์ด๋ธ”์˜ countUnavailableSeatsGroupByScheduleId()

select schedule_id, COUNT(schedule_id)
from Seat
where status = 'UNAVAILABLE'
group by schedule_id;

seat ํ…Œ์ด๋ธ”์—์„œ ์ƒํƒœ๊ฐ€ 'UNAVAILABLE'์ธ ์ขŒ์„์„ ์Šค์ผ€์ค„๋ณ„๋กœ ๊ทธ๋ฃนํ™”ํ•˜์—ฌ COUNTํ•˜๋Š” ์ฟผ๋ฆฌ์ž…๋‹ˆ๋‹ค.

 

 

์ธ๋ฑ์‹ฑ ์ „

Explain ๊ฒฐ๊ณผ
์ฟผ๋ฆฌ ์ˆ˜ํ–‰ ์‹œ๊ฐ„

 

status ์ปฌ๋Ÿผ์— ์ธ๋ฑ์Šค๊ฐ€ ์—†๋Š” ์ƒํƒœ์—์„œ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•œ ๊ฒฐ๊ณผ, ์‹คํ–‰ ์†๋„๋Š” 1s 825ms๊ฐ€ ์†Œ์š”๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

๊ฐœ๋ณ„ ์ธ๋ฑ์‹ฑ ํ›„

CREATE INDEX idx_schedule_id ON seat(schedule_id);
CREATE INDEX idx_status ON seat(status);

Explain ๊ฒฐ๊ณผ
์ฟผ๋ฆฌ ์ˆ˜ํ–‰ ์‹œ๊ฐ„

 

๋จผ์ € schedule_id์™€ status ์ปฌ๋Ÿผ์— ๊ฐœ๋ณ„ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์‹คํ–‰ ์†๋„๋Š” 49ms๋กœ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹คํ–‰ ๊ณ„ํš ๊ฒฐ๊ณผ์˜ Extra๋ฅผ ๋ณด๋ฉด ์ธ๋ฑ์Šค๊ฐ€ ์ „์ฒด์ ์ธ ๋ฒ”์œ„ ์กฐ๊ฑด์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์•„ ์—ฌ์ „ํžˆ ์ž„์‹œ ํ…Œ์ด๋ธ”๊ณผ ํŒŒ์ผ ์ •๋ ฌ์ด ์‚ฌ์šฉ๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. 

 

 

๋ณตํ•ฉ ์ธ๋ฑ์‹ฑ ํ›„

CREATE INDEX idx_status_schedule_id ON seat(status, schedule_id);

 

Explain ๊ฒฐ๊ณผ
์ฟผ๋ฆฌ ์ˆ˜ํ–‰ ์‹œ๊ฐ„

 

์ดํ›„ status์™€ schedule_id ์ปฌ๋Ÿผ์— ๋ณตํ•ฉ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์„ ๋‹ค์‹œ ์ธก์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ณตํ•ฉ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋‹ˆ ์ž„์‹œ ํ…Œ์ด๋ธ”๊ณผ ํŒŒ์ผ ์ •๋ ฌ ์—†์ด GROUP BY์™€ WHERE ์กฐ๊ฑด์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ , ์‹คํ–‰ ์†๋„๋Š” 33ms๋กœ ํฌ๊ฒŒ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

 

3. Reservation ํ…Œ์ด๋ธ”์˜ findAllByExpiresAtBeforeAndStatus()

SELECT *
FROM reservation
WHERE expires_at < '2024-11-20 00:00:00' AND status = 'PENDING';

์˜ˆ์•ฝ ํ…Œ์ด๋ธ”์—์„œ ๋งŒ๋ฃŒ ์‹œ๊ฐ„๊ณผ ์ƒํƒœ ์กฐ๊ฑด์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์˜ˆ์•ฝ ํ…Œ์ด๋ธ”์—๋„ ๋ฐฑ๋งŒ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•œ ํ›„ ์ธ๋ฑ์Šค ์ถ”๊ฐ€ ์ „ํ›„๋ฅผ ๋น„๊ตํ–ˆ์Šต๋‹ˆ๋‹ค.

 

 

์ธ๋ฑ์‹ฑ ์ „

Explain ๊ฒฐ๊ณผ
์ฟผ๋ฆฌ ์ˆ˜ํ–‰ ์‹œ๊ฐ„

 

expires_at๊ณผ status ์กฐ๊ฑด์— ๋Œ€ํ•ด ์ธ๋ฑ์Šค๊ฐ€ ์—†์„ ๋•Œ ์‹คํ–‰ ์†๋„๋Š” 99ms์˜€์Šต๋‹ˆ๋‹ค.

 

 

๋ณตํ•ฉ ์ธ๋ฑ์Šค ์ถ”๊ฐ€ ํ›„

 

1. idx_expiresAt_status ์‹œ๋„

CREATE INDEX idx_expiresAt_status ON reservation (expires_at, status);

Explain ๊ฒฐ๊ณผ
์ฟผ๋ฆฌ ์ˆ˜ํ–‰ ์‹œ๊ฐ„

 

์ฒ˜์Œ์—๋Š” expires_at๊ณผ status์˜ ์ˆœ์„œ๋กœ ๋ณตํ•ฉ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ฟผ๋ฆฌ ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ์ด ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” expires_at์ด ๋ฒ”์œ„ ์กฐ๊ฑด์œผ๋กœ ์‚ฌ์šฉ๋˜๋ฉด์„œ ์ธ๋ฑ์Šค์˜ ํšจ์œจ์ด ๋–จ์–ด์กŒ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

 

 

2. idx_status_expiresAt ์‹œ๋„

 

Explain ๊ฒฐ๊ณผ
์ฟผ๋ฆฌ ์ˆ˜ํ–‰ ์‹œ๊ฐ„

 

์ดํ›„ ์ธ๋ฑ์Šค ์ˆœ์„œ๋ฅผ status, expires_at๋กœ ๋ณ€๊ฒฝํ•˜์ž, status ์กฐ๊ฑด์œผ๋กœ ๋จผ์ € ํ•„ํ„ฐ๋งํ•œ ํ›„ expires_at์„ ์ด์šฉํ•ด ๋ฒ”์œ„๋ฅผ ์ขํžˆ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ธ๋ฑ์Šค๊ฐ€ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜์—ˆ๊ณ , ์‹คํ–‰ ์†๋„๋Š” 66ms๋กœ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

 

 

๊ฒฐ๋ก 

์ด๋ฒˆ ์ตœ์ ํ™” ๊ณผ์ •์„ ํ†ตํ•ด ๋ณตํ•ฉ ์ธ๋ฑ์Šค์˜ ์ˆœ์„œ๊ฐ€ ์ฟผ๋ฆฌ์˜ ํšจ์œจ์„ฑ์— ํฐ ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ status์™€ expires_at์˜ ๋ณตํ•ฉ ์ธ๋ฑ์Šค์—์„œ, ์ฟผ๋ฆฌ ์กฐ๊ฑด์— ๋งž๋Š” ์ˆœ์„œ๋กœ ์ธ๋ฑ์Šค๋ฅผ ์„ค๊ณ„ํ•ด์•ผ ์ธ๋ฑ์Šค๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‚ฌ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ตœ์ข…์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ธ๋ฑ์Šค๋ฅผ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

CREATE INDEX idx_schedule_id ON seat(schedule_id);
CREATE INDEX idx_status_schedule_id ON seat(status, schedule_id);
CREATE INDEX idx_status_expiresAt ON reservation (status, expires_at);

 

์œ„ ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•ด ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์ฟผ๋ฆฌ์˜ ์„ฑ๋Šฅ์„ ์•„๋ž˜์™€ ๊ฐ™์ด ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ฟผ๋ฆฌ ์ธ๋ฑ์‹ฑ ์ „ ์‹คํ–‰ ์‹œ๊ฐ„ (ms) ์ธ๋ฑ์‹ฑ ํ›„ ์‹คํ–‰ ์‹œ๊ฐ„ (ms)
findAllByScheduleId() 352 65
countUnavailableSeatsGroupByScheduleId() 1825 33
findAllByExpiresAtBeforeAndStatus() 99 66

 

 

 

๋งˆ์น˜๋ฉฐ

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์ฝ˜์„œํŠธ ์˜ˆ์•ฝ ์„œ๋น„์Šค์˜ ์ฃผ์š” ์ฟผ๋ฆฌ๋ฅผ ๋ถ„์„ํ•˜๊ณ , ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ธ๋ฑ์Šค ์„ค๊ณ„ ์‹œ์—๋Š” ๋ฐ์ดํ„ฐ ๋ถ„ํฌ์™€ ์ฟผ๋ฆฌ ํŒจํ„ด์„ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋ฉฐ, ์ธ๋ฑ์Šค์˜ ์ปฌ๋Ÿผ ์ˆœ์„œ๋„ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์— ํฐ ์˜ํ–ฅ์„ ๋ฏธ์น  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.