2024. 5. 2. 15:48γDatabase
μλ‘
νμ¬ μ λ μ§μΈ 3λΆκ³Ό ν¨κ» κ°λ¨ν ν νλ‘μ νΈλ₯Ό μ§ν μ€μΈλ°, κ·Έ κ³³μμ μ§ν μ€μΈ ‘ν°μΌν μλΉμ€’ νλ‘μ νΈμμ νμκ° λΆνκ° λͺ°λ¦¬λ ν°μΌν νκ²½μμλ ꡬ맀μ μ ν©μ±μ 보μ₯νκΈ° μν΄ λ Έλ ₯νκ³ μμ΅λλ€. λΏλ§ μλλΌ μ±λ₯μ μΈ κ°μ λ μ΄λ£¨μ΄λ΄κΈ° μν΄ λ€μν λ Όμλ€μ μ§ννκ³ μμ΅λλ€. ν΄λΉ κΈμμλ μ±λ₯ κ°μ μ μν΄ λ°μ΄ν°λ² μ΄μ€ λ΄μμ ν°μΌ λ μ½λλ₯Ό μ½μ΄μ€λ λ°©μμ κ°μ νκ³ κΈ°μ‘΄ λ°©μκ³Ό μ±λ₯μ μΌλ‘ λΉκ΅ν λ΄μ©μ λ€λ£¨κ³ , μ΅μ’ μ μΌλ‘λ μ΄λ₯Ό ν΅ν΄ μ ν¬ μλΉμ€μ λ―ΈμΉ μν₯μ λν΄ μ΄μΌκΈ°ν΄λ³΄λλ‘ νκ² μ΅λλ€.
λ€μ΄κ°κΈ° μμ
본격μ μΈ μ±λ₯ λΉκ΅μ μμ νμ¬ νλ‘μ νΈμμ ν°μΌν μ΄ μ΄λ£¨μ΄μ§λ λ°©μμ λν΄ κ°λ¨ν μ€λͺ νκ² μ΅λλ€.
μλΉμ€ λ΄ ν°μΌν κ΄λ ¨ λ‘μ§μ μ°Έμ¬νλ ν μ΄λΈ κ° κ°λ΅νν ERDλ μμ κ°μ΅λλ€.
μλλ ν°μΌ ꡬ맀μ κ΄λ ¨λ λλ΅μ μΈ νλ¦μ λλ€.
- ν맀μκ° ν°μΌν μ μμ±ν λ ν맀ν ν°μΌμ κ°μλ§νΌ DB λ΄ λ μ½λκ° μμ±λ©λλ€.
- ꡬ맀μλ ꡬ맀ν ν°μΌμ μμ ν¨κ» ꡬ맀 μμ²μ 보λ΄κ² λ©λλ€.
- ν°μΌμ λν λμμ±μ κ³ λ €νκΈ° μν΄ ν°μΌμ DBμμ μ½μ΄μ¬ λ λ½μ ν΅ν΄ ꡬ맀ν ν°μΌ κ°μλ§νΌ μ½μ΄μ΅λλ€.
- ꡬ맀 λ μ½λλ₯Ό μμ±νκ³ κ·Έμ ν¨κ» ν°μΌμ ν΄λΉ ꡬ맀λ₯Ό λ°°μ ν©λλ€.
μ΄ κ³Όμ μμ μ κ° νμΈνκ³ μ νλ μ±λ₯ κ°μ ν¬μΈνΈλ λ½μ κ±Έκ³ ν°μΌμ κ°μ Έμ€λ κ³Όμ μ λλ€.
λ³Έλ‘
κΈ°μ‘΄ λ°©μ
κΈ°μ‘΄μ ꡬννλ ν°μΌμ κ°μ Έμ€λ λ ν¬μ§ν 리 λ©μλλ μλμ κ°μ΅λλ€.
(μλΉμ€ λ΄ ν΄λΉ λ‘μ§μ λΉκ΄μ λ½κ³Ό λκ΄μ λ½, κ·Έλ¦¬κ³ λΆμ°λ½μΌλ‘ λͺ¨λ ꡬνλμ΄ μμ§λ§ λ½μ νΉμ± μ ν΄λΉ κ°μ μ λκ΄μ λ½μ κ²½μ°μ κ°μ₯ ν° μ°¨μ΄κ° μ‘΄μ¬ν κ²μ΄λΌ μκ°νμ΅λλ€.)
μ λ©μλλ₯Ό νΈμΆνλ©΄ μλ μΏΌλ¦¬κ° λκ°κ² λ©λλ€.
SELECT *
FROM tickets
WHERE
ticketing_id = :ticketingId
AND
purchase_id IS NULL
ORDER BY ticket_id
LIMIT :limit;
μ΄ μΏΌλ¦¬λ λͺ©ν λ μ½λλ₯Ό μ‘°ννλλ° κ²°κ΅ ν°μΌ ID μμΌλ‘ μ‘°ννκΈ° λλ¬Έμ λμλ€λ°μ μΈ κ΅¬λ§€κ° λ°μνμ λ λͺ¨λ μ μ λ€μ΄ κ°μ ν°μΌμ λ°λΌλ³΄κ²λ©λλ€. λ°λΌμ λͺ¨λ μ μ λ€μ μμ²μ΄ κ°μ ν°μΌμ λκ΄μ λ½μ κ±°λ κ²μ΄κΈ° λλ¬Έμ λμμ±μ΄ λ§μ΄ μ νλ κ²μΌλ‘ μμνμ΅λλ€.
ORDER BYμ μ λΊλ€λ©΄?
κ·Έλ λ€λ©΄ ORDER BYλ₯Ό λΉΌλ©΄λλ κ² μλλκ³ ν μ μμ§λ§, MySQLμ νΉμ± μ ν΄λ¬μ€ν°λ§ μΈλ±μ€λ₯Ό μννκ² λκ³ μ묡μ μΌλ‘ ORDER BY ticket_idκ° μ‘΄μ¬νλ κ²μΌλ‘ λ³Ό μ μμ΅λλ€. λ°λΌμ ORDER BY μ μ λΉΌλλΌλ λμΌνκ² λμν©λλ€.
κ°μ λ°©μ
맀 μμ²λ§λ€ κ°μ ν°μΌμ λ½μ κ±°λ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄μλ ν°μΌ ν μ΄λΈ λ΄μμ λ μ½λλ₯Ό λλ€νκ² μΆμΆν νμκ° μλ€κ³ μκ°νμ΅λλ€.
MySQLμμ μ΄λ₯Ό μν΄μλ μλμ²λΌ 쿼리λ₯Ό μμ±νλ©΄ λ©λλ€.
SELECT *
FROM tickets
WHERE
ticketing_id = :ticketingId
AND
purchase_id IS NULL
ORDER BY RAND()
LIMIT :limit;
κ·Έλ¦¬κ³ ν΄λΉ 쿼리λ₯Ό μ€νμν€κΈ° μν΄μλ μλμ²λΌ JPQLμ μμ±νλ©΄ λ©λλ€.
ν μ€νΈ λ°©μ
λμΆν κ°μ λ°©μκ³Ό κΈ°μ‘΄ λ°©μμ μ±λ₯μ λΉκ΅νκΈ° μν΄ ν μ€νΈ μ€κ³κ° νμνμ΅λλ€.
μ΄λ₯Ό μν΄ Executorμ CountDownLatchλ₯Ό νμ©ν ν μ€νΈλ₯Ό μλμ²λΌ μμ±ν΄μ£Όμμ΅λλ€.
κ·Έ ν ν μ€νΈ μ λ³μΈμ μμ ν΄μΌ νλλ°, μ λ μ΄λ₯Ό νΉμ ν°μΌν μ΄νμ ν°μΌ μλ‘ μ‘μμ΅λλ€.
κ·Έ μ΄μ λ ν°μΌμ κ°μ Έμ€λ 쿼리μ μ±λ₯μ κ°μ₯ ν° μν₯μ λ―ΈμΉλ μμκ° λ°λ‘ κ·Έκ²μ΄κΈ° λλ¬Έμ λλ€. μ΄μ λ°λΌ μ€μ ν°μΌν μν©μ μμ νμ¬ κ°κ° 300(μνκ΄ κ·λͺ¨), 3000(μ¬λ¦Όν½ ν κ·λͺ¨), 30000(μΌκ΅¬μ₯ κ·λͺ¨)μ ν°μΌ μλ₯Ό κ°μ§κ³ κ°κ° ν μ€νΈλ₯Ό μ§ννμμ΅λλ€.
ν°μΌ μ μΈ μμΈλ€μ λν΄μλ νΉμ κ°μΌλ‘ κ³ μ ν λ€ ν μ€νΈλ₯Ό μ§ννμ΅λλ€.
- λμ ν°μΌν μ μ μ: 20 (νλ‘μ νΈ λκΈ°μ΄ μ μ± μ κΈ°λ°ν κ°λ₯ν κ° λ΄ μ ν)
- κ° μ μ λΉ ν°μΌ ꡬ맀 μ: 3 (μμμ κ°)
λν λκ΄μ λ½ λ°©μμ΄κΈ° λλ¬Έμ λμμ± μμΈκ° λ°μνμ κ²½μ° μ΄μ λν μμΈμ²λ¦¬κ° νμν©λλ€. μ λ @Retryable μ΄λ Έν μ΄μ μΌλ‘ μ€ν¨ μ ꡬ맀 λ‘μ§μ λ€μ μ€νμν€λ λ°©μμ μ¬μ©νμ΅λλ€. λν λ°©μ λ³ λΉκ΅λ₯Ό μν΄ μ΅μ’ μ¬μλ νμλ₯Ό λ°νν΄μ£Όμμ΅λλ€.
μ΄ λ @Retryable κ΄λ ¨ μ€μ μ μλμ κ°μ΅λλ€.
- backoff(μ€ν¨ μ μ¬μλκΉμ§ λλ μ΄): 50ms
- maxAttempts(μ΅λ μ¬μλ νμ): 100ν
ν μ€νΈ κ²°κ³Ό
λͺ¨λ μ μ μ ν°μΌν μ΄ μλ£λκΈ°κΉμ§ κ±Έλ¦° μκ°κ³Ό μ¬μλ νμλ₯Ό κ° μΌμ΄μ€ λ³λ‘ νμΈνλ©΄ μλμ κ°μ΅λλ€.
ν°μΌ μ | κΈ°μ‘΄ λ°©μ | λλ€ μΆμΆ λ°©μ | ||
μμ μκ° | κ²½ν© λ°μ νμ | μμ μκ° | κ²½ν© λ°μ νμ | |
300κ° | 761ms | 59ν | 98ms | 2ν |
3000κ° | 666ms | 55ν | 106ms | 1ν |
30000κ° | 979ms | 75ν | 120ms | 0ν |
ν μ€νΈ ν΄μ
κΈ°μ‘΄ λ°©μμ ν μ€νΈ κ²°κ³Όλ₯Ό ν΄μν΄λ³΄μλ©΄, κ²°κ΅ ν°μΌμ μλ§ μ¦κ°νκ³ μλ μ μ μμ μμ μμ μκ°μ΄ λͺ¨λ λΉμ·ν©λλ€.
SELECT *
FROM tickets
WHERE
ticketing_id = :ticketingId
AND
purchase_id IS NULL
ORDER BY ticket_id
LIMIT :limit;
μ΄λ₯Ό ν΄μνκΈ° μν΄μλ κΈ°μ‘΄ λ°©μμ μΏΌλ¦¬κ° λμνλ λ°©μμ μ΄ν΄ν΄μΌ νλλ°, PK κΈ°μ€μΌλ‘ μ λ ¬λ κ° μ€ 3κ°μ λ μ½λλ₯Ό κ°μ Έμ€λ κ²μ΄ λͺ©μ μ΄κΈ° λλ¬Έμ κ²°κ΅μ ν΄λ¬μ€ν°λ§ μΈλ±μ€λ₯Ό νμ€μΊνλ©΄μ 쑰건μ λ§μ‘±νλ λ μ½λλ₯Ό 3κ° μ°Ύλ μκ° κ³§λ°λ‘ μ€νμ΄ μ’ λ£λλ 쿼리μ λλ€.
λ°λΌμ λ μ½λκ° λ§μμ§λλΌλ ν°μΌν μ΄ νλ μλ μν©μμλ λͺ¨λ λΉμ·ν μ±λ₯μ 보μ λλ€. μ΄λ¬ν μν©μ ν°μΌν μ΄ λ μ΄μ μλ μν©μμλ κΉ¨μ§κ² λλλ° μ΄ λν tickets ν μ΄λΈ λ΄ ticketing_idμ μΈλ±μ€λ₯Ό κ±Έμ΄μ£Όλ λ°©μμΌλ‘ μ΅μ νκ° κ°λ₯ν©λλ€.
μ¦, ν°μΌμ μ‘°ννλ κ² μ체λ μ΄λμ λ μ΅μ νκ° μ΄λ£¨μ΄μ Έμλ€κ³ λ³Ό μ μμ΅λλ€. νμ§λ§ λ¬Έμ λ λ°λ‘ λ³Έλ‘ μλμμ μΈκΈν λͺ¨λ νΈλμμ μ΄ λμΌν ν°μΌ λ μ½λλ₯Ό λ°λΌλ³΄λ κ²μ λλ€. μ΄λ‘ μΈν΄ λΆνμν κ²½ν©μ΄ λ°μνκ² λκ³ , μ΄λ₯Ό ν΅ν λ°λ³΅μ μΈ μ¬μλλ₯Ό ν΅ν΄ κ²°λ‘ μ μΌλ‘λ μ±λ₯μ΄ μ’μ§ μμ λͺ¨μ΅μ 보μ΄κ³ μμ΅λλ€.
λ°λ©΄, μμ λ 쿼리λ ν° μ°¨μ΄λ μλλ ν°μΌμ μκ° μ¦κ°ν¨μ λ°λΌ μΌμ νκ² μ€ν μκ°μ΄ λμ΄λκ³ μμ΅λλ€.
SELECT *
FROM tickets
WHERE
ticketing_id = :ticketingId
AND
purchase_id IS NULL
ORDER BY RAND()
LIMIT :limit;
μ΄λ μ μΏΌλ¦¬κ° PKλ₯Ό κΈ°μ€μΌλ‘ μ λ ¬λ 3κ°μ λ μ½λλ₯Ό κ°μ Έμ€λ κ²μ΄ μλλΌ, 쑰건μ λ§μ‘±νλ λͺ¨λ λ μ½λμ λλ€ κ°μ λΆμ¬νκ³ μ΄λ₯Ό κΈ°μ€μΌλ‘ μ λ ¬μ μννκΈ° λλ¬Έμ μ΄ κ³Όμ μμ λ°μ΄ν°μ μλ§νΌ μ°μ°λμ΄ λμ΄λκΈ° λλ¬Έμ λλ€. λ°λΌμ μ΄ λΆλΆμ μ΄ν ν μ΄λΈ λ΄ λ°μ΄ν°κ° λ§μμ§μ λ°λΌ μΆκ°μ μΈ μ±λ₯ κ°μ μ ν¬μΈνΈλ‘ μ‘μ μ μμ΄λ³΄μ λλ€.
λ€λ§ κ·ΈλΌμλ λΆκ΅¬νκ³ , κΈ°μ‘΄ λ°©μκ³Ό λΉκ΅νμ λ μ¬μλ νμ(κ²½ν© νμ)κ° μμ²λκ² μ€μ΄λ€μ΄ κ²°λ‘ μ μΌλ‘ μ±λ₯ κ°μ μ κ΅μ₯ν λ§μ΄ λ κ²μ λ³Ό μ μμ΅λλ€. (μ½ 8λ°° κ°μ )
κ²°λ‘
λκ΄μ λ½μ κ²½ν©μ΄ λ§μ΄ λ°μν μλ‘ μ±λ₯μ΄ λλΌλ§ν±νκ² λλΉ μ§λ νΉμ±μ κ°κΈ° λλ¬Έμ, κ°μ 쑰건μμ κ²½ν©μ μ€μΌ μ μλ€λ©΄ λκ΄μ λ½ λ‘μ§μ μ±λ₯ κ°μ μ μ΄λ£¨μ΄λΌ μ μλ€κ³ μκ°νμ΅λλ€.
μ λ μ΄λ₯Ό λ°νμΌλ‘ μ ν¬κ° μ΄κΈ° ꡬνν λ°©μμ κ²½μ° λΆνμν κ²½ν©μ΄ κ³Όλνκ² λ§μ΄ λ°μν κ²μΌλ‘ μμνμ¬ κΈ°μ‘΄κ³Όλ λ€λ₯Έ λ°©μμΌλ‘ ν°μΌ μΆμΆμ μ§νν΄μΌ νλ€κ³ μκ°νμ¬ ν΄λΉ ν μ€νΈλ₯Ό μ§ννμκ³ , κ²°λ‘ μ μΌλ‘ μ ν μ€νΈ κ²°κ³Όλ€μ ν΅ν΄ λ μ½λλ₯Ό λλ€νκ² μΆμΆνλ λ°©μμ΄ κ²½ν©μ μ€μ΄λλ° ν° λμμ μ€λ€λ κ²μ νμΈν μ μμμ λΏ μλλΌ μ΄λ₯Ό ν΅ν΄ κ²½ν© μ ν°μΌ ꡬ맀 μ±λ₯μ μ½ 8λ°° κ°μ ν μ μμκ³ , μ΅μ’ μ μΌλ‘λ μ ν¬ μλΉμ€κ° λκ΄μ , λΉκ΄μ , λΆμ° λ½ μ€ μ΄λ€ λ½μ μ νν μ§ κ³ λ €νλ λ¨κ³μμ λκ΄μ λ½μ μ ννλλ° ν° κΈ°μ¬λ₯Ό νμμ΅λλ€.
(νλ‘μ νΈ λ΄ λ½ μ ν κ΄λ ¨ λ¬Έμ: https://tiketeer.notion.site/cd390c746077406eb352947875df9457)
'Database' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
Database PK μμ± μ λ΅ (without DB, Mysql) (3) | 2024.03.17 |
---|---|
νμ΄μ§λ€μ΄μ λ°©λ²λ‘ λΉκ΅(Offset vs Cursor) (0) | 2024.02.17 |
JOINμ μ λ§ λλ¦°κ° (μμ κ·ν) (0) | 2024.01.07 |
Slow Query νμΈλ² (in Mysql, Postgresql) (0) | 2023.12.13 |