2024. 2. 17. 17:17γDatabase
νμ΄μ§λ€μ΄μ μ΄λ?
OLTP νκ²½μμ μ¬μ©μμκ² λ°νλλ λ°μ΄ν°λ€μ λλΆλΆ νΉμ κΈ°μ€μΌλ‘ μ λ ¬λ μΌλΆ λ°μ΄ν°μ΄λ€.
μλ₯Ό λ€λ©΄ μΉκ°λ°μ κ°μ₯ νν μμμΈ κ²μνμ΄ κ·Έλ λ€. κ²μνμ μΌλ°μ μΌλ‘ ν νμ΄μ§μ μ½ 20κ°μ κ²μκΈλ€μ μ΅μ μμΌλ‘ λ ΈμΆμν€κ³ , μ¬μ©μκ° λ€μ νμ΄μ§λ‘ λμ΄κ°κ² λλ©΄ 21 ~ 40λ²μ§Έ λ°μ΄ν°κ° κ·Έμ μμΌ μ‘°νλλ λ°©μμΌλ‘ ꡬνλλ€.
μ΄ μν©μμ μλ²λ μ¬μ©μμκ² μ 체 κ²μκΈ λ°μ΄ν°λ₯Ό μ λ¬νλ κ²μ΄ μλ, μ¬μ©μκ° μμΉν νμ΄μ§μ ν΄λΉνλ λ°μ΄ν°λ§μ λ°ννλλ‘ API μ€κ³κ° μ΄λ£¨μ΄μ§λλ° μ΄λ₯Ό νμ΄μ§λ€μ΄μ λ°©λ²λ‘ μ΄λΌκ³ λΆλ₯Έλ€.
νμ΄μ§λ€μ΄μ μ’ λ₯
μΌλ°μ μΌλ‘ λ§μ΄ μ¬μ©λλ νμ΄μ§λ€μ΄μ κΈ°λ²μλ Offset κΈ°λ° νμ΄μ§λ€μ΄μ κ³Ό Cursor(Keyset) κΈ°λ° νμ΄μ§λ€μ΄μ μ΄ μ‘΄μ¬νλ€.
Offset κΈ°λ°
Offset κΈ°λ° νμ΄μ§λ€μ΄μ κΈ°λ²μ νμ΄μ§λ€μ΄μ μ λ€λ£° λ κ°μ₯ λ§μ΄ λ±μ₯νλ λ°©μμ΄λ€.
λ°λ‘ μμμ μμλ‘ λ κ²μν ꡬνμλ μ£Όλ‘ μ΄ λ°©μμ΄ μ¬μ©λλ€.
μμλ₯Ό μν΄ post ν μ΄λΈμ΄ μλμ κ°μ΄ μμ±λμ΄ μλ€κ³ κ°μ νμ. μ΄ λ μ 체 row μλ 50,000μ΄κ³ , κΈ°μ€ DBλ Mysqlμ΄λ€.
CREATE TABLE post (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
name VARCHAR(30),
content TEXT,
created_at TIMESTAMP
);
CREATE INDEX idx_post_created_at ON post(created_at);
μ΄ λ Offset κΈ°λ° νμ΄μ§λ€μ΄μ 쿼리λ μλμ κ°μ΄ μμ±λλ€.
SELECT *
FROM post
ORDER BY created_at DESC
LIMIT 20 OFFSET 20 * {page - 1};
μΏΌλ¦¬κ° μλΉν κ°λ¨νκ² κ΅¬μ±λλλ°, μ΄λ Offset κΈ°λ° νμ΄μ§λ€μ΄μ μ μ₯μ μ€ νλμ΄λ€. ν΄λΌμ΄μΈνΈ μΈ‘μμλ νμ΄μ§λ€μ΄μ μ ꡬννκΈ° μν΄ μλ² μΈ‘μ λ¨μν νμ΄μ§ μ 보μ νμ΄μ§ λΉ λ°μ΄ν° μ, λ§μ§λ§μΌλ‘ μ λ ¬ κΈ°μ€ λ§μ μ λ¬νλ©΄ λλ€.
μ μΏΌλ¦¬λ‘ μ²«λ²μ§Έ νμ΄μ§λ₯Ό μ‘°ννλ μν©μ μ€ν κ³νμ μλμ κ°λ€.
μ€ν κ³νμ μ보면 μΏΌλ¦¬κ° DBμμ μ κ·Όν rows μκ° λ¨ 20μ κ·ΈμΉλ κ²μ μ μ μλ€. μ΄λ μ 체 50,000κ°μ rowλ₯Ό μ λΆ νμΈνμ§ μκ³ νμν λΆλΆλ§μ μ½μ΄λ΄κ³ μλ€κ³ λ³Ό μ μλ€. μ΄λ μΈλ±μ€λ₯Ό ν΅ν΄ μ΄λ―Έ μ λ ¬μ΄ λμ΄ μλ μν©μμ λ± νμν λ°μ΄ν° λ§νΌμ μ½μ μ μμκΈ° λλ¬Έμ΄λ€.
μ΄λ¬ν ν¨ν΄ λλ¬Έμ μ΅μ νλ Offset κΈ°λ° νμ΄μ§λ€μ΄μ νκ²½μμλ ν μ΄λΈμ λ°μ΄ν°κ° μ무리 λ§μλ 첫λ²μ§Έ νμ΄μ§λ₯Ό μ½μ΄μ€λλ° μ€λκ±Έλ¦¬μ§ μλλ€.
μ΄μ λλ²μ§Έ νμ΄μ§λ₯Ό μ‘°ννλ μ€ν κ³νμ νμΈν΄λ³΄μ.
μ΄λ²μλ 20κ°μ λ°μ΄ν°λ§μ μ½μ κ²μΌλ‘ μκ°ν μ μμ§λ§ LIMIT OFFSET 쿼리λ κ·Έλ κ² λμνμ§ μλλ€.
λ§μ½ LIMIT A OFFSET BλΌκ³ νλ€λ©΄, DB μ΅ν°λ§μ΄μ λ A+Bλ§νΌμ λ°μ΄ν°λ₯Ό ν μ΄λΈμμ μ½μ΄λΈ λ€ λΆνμν λΆλΆμ λ²λ¦¬λ μμΌλ‘ λμνλ€. DBκ° μΈλ±μ€ νμμ μνν λ μ€νμ μ 보λ₯Ό μμ§μ νμμ μ΄μ©ν μ μκΈ° λλ¬Έμ μ΄μ κ°μ΄ λμνλ€.
λ°λΌμ Offset κΈ°λ° νμ΄μ§λ€μ΄μ μ νμ΄μ§κ° λ€λ‘ κ°μλ‘ μ½μ΄μΌ ν λ°μ΄ν°μ μ΄λμ΄ λ§μμ Έ μ±λ₯μ΄ μ νλλ νΉμ±μ κ°λλ€.
μμ½
- ꡬν, 쿼리 ꡬμ±μ΄ μλΉν κ°λ¨νλ€.
- μ΅μ νλ Offset κΈ°λ° νμ΄μ§λ€μ΄μ νκ²½μμλ ν μ΄λΈ λ΄ λ°μ΄ν°κ° μ무리 λ§μλ 첫 νμ΄μ§ λ°μ΄ν°λ₯Ό κ°μ Έμ€λλ° μ€λκ±Έλ¦¬μ§ μλλ€.
- νμΈν΄μΌ ν νμ΄μ§κ° λ€λ‘ κ°μλ‘, μ½μ΄μΌ νλ λ°μ΄ν°μ μ΄λμ΄ μ νμ μΌλ‘ μ¦κ°νμ¬ μ±λ₯μ΄ μ νλλ€.
Cursor(Keyset) κΈ°λ°
Cursor κΈ°λ° νμ΄μ§λ€μ΄μ κΈ°λ²μ 무ν μ€ν¬λ‘€μ ꡬνν λ νν μ ν μ μλ λ°©μμ΄λ€.
μμμ μ¬μ©ν ν μ΄λΈμ κ·Έλλ‘ μ¬μ©νλ μν©μμ Cursor κΈ°λ° νμ΄μ§λ€μ΄μ 쿼리λ μλμ²λΌ μμ±ν μ μλ€.
SELECT *
FROM post
WHERE created_at < {:cursor}
ORDER BY created_at DESC
LIMIT 20;
μ 쿼리λ₯Ό 보면 μ μ μμ§λ§, Cursor κΈ°λ° νμ΄μ§λ€μ΄μ μ ꡬννκΈ° μν΄μλ ν΄λΌμ΄μΈνΈ μΈ‘μμ 컀μ λ°μ΄ν°λ₯Ό λ°λ‘ μ μ§νλ€κ° μμ² μ ν¬ν¨ν΄μ£Όμ΄μΌ νλ€. μ μμμμλ ν¬κ² μ΄λ €μ보μ΄μ§ μμ§λ§, μ λ ¬ κΈ°μ€μ΄ λ§μμ§λ νκ²½μμλ ν΄λΌμ΄μΈνΈ μΈ‘μ΄λ μλ² μΈ‘ λͺ¨λ ꡬνμ λΆλ΄μ΄ λ μ μλ€.
ν΄λΉ λ°©μμ νμ©ν λ κ°μ₯ λ¨Όμ μ€νλλ 쿼리μ μ€ν κ³νμ μλμ κ°λ€.
μ€ν κ³νμ 보면 Offset κΈ°λ° νμ΄μ§λ€μ΄μ λ°©μμ 1νμ΄μ§ μμ² μΏΌλ¦¬μ μμ ν λμΌνλ€. μ΄λ₯Ό ν΅ν΄ Cursor κΈ°λ° νμ΄μ§λ€μ΄μ λ°©μ λν ν μ΄λΈμ μ λΆ νμΈνλ κ²μ΄ μλλΌ νμν λΆλΆμ λ°μ΄ν° λ§μ ν¨μ¨μ μΌλ‘ μ½μ μ μμμ μ μ μλ€.
μ΄μ μ€ν¬λ‘€μ μ‘°κΈ λ λ΄λ €μ λ€μ 20κ°μ λ°μ΄ν°λ₯Ό λΆλ¬μ€λ μν©μ 쿼리λ₯Ό μμ±ν΄λ³΄μ. μ 쿼리λ₯Ό μ€ννμ λ λ§μ§λ§ λ°μ΄ν°μ created_at μΉΌλΌ κ°μ '2023-12-30 10:35:25' μ΄λ―λ‘ μ΄λ₯Ό 컀μλ‘ νμ©νμ. μ€ν κ³νμ μλμ κ°λ€.
νμ΄μ§μ κ°μ΄ 컀μ§μ λ°λΌ μ½μ΄μΌ νλ λ°μ΄ν°μ μλ μ νμ μΌλ‘ μ¦κ°νλ Offset κΈ°λ° λ°©μκ³Όλ λ¬λ¦¬, Cursor κΈ°λ° λ°©μμ μ¬μ ν 20κ°μ rowλ§μ μ½μ΄λΈλ€. μ΄λ DBκ° μ»€μ κ°μ ν΅ν΄ μΈλ±μ€ νμ μμ μ§μ μ 곧λ°λ‘ μ°Ύμ μ μκΈ° λλ¬Έμ κ°λ₯ν μΌμ΄λ€. λ°λΌμ ν΄λΉ λ°©μμ 컀μκ° λ€λ‘ λ§μ΄ κ° μν©μμλ νμ μΌμ ν μ±λ₯μ 보μ₯νλ νΉμ±μ κ°λλ€.
κ·Έλ λ€λ©΄ ꡬν λμ΄λμ μΈ λ¬Έμ λ§ ν΄κ²°νλ©΄ νμ Cursor κΈ°λ° νμ΄μ§λ€μ΄μ μ μ¬μ©ν΄μΌ νλ κ²μ΄ μλλκ³ μ΄μΌκΈ°ν μ μλ€. νμ§λ§ μ΄μλ μ μ½μ΄ μ‘΄μ¬νλ€. λμΉκ° λΉ λ₯Έ μ¬λλ€μ΄λΌλ©΄ μ΄λ―Έ μμμ±κ² μ§λ§, μ μμ 쿼리λ ν° λ¬Έμ λ₯Ό μκ³ μλ€. λ§μ½ μμ ν κ°μ μμ μ μμ±λ postκ° μ‘΄μ¬νμ¬ created_at μΉΌλΌμ΄ μμ ν λμΌν rowκ° μ‘΄μ¬ν μ μλ€λ©΄? μ΄ κ²½μ° Cursor κΈ°λ° λ°©μμ μΆλ ₯ λ°μ΄ν°μ μΌκ΄μ±μ 보μ₯ν μ μλ€. cursor κ°μΌλ‘ μ¬μ©λλ λ°μ΄ν° μ§ν©μ ν μ΄λΈ μμμ μ μΌμ±μ΄ 보μ₯λμ΄μΌ νλ€λ κ²μ΄λ€. λ¬Όλ‘ cursor μ μ μΉΌλΌμ μΆκ°νμ¬ μ μΌμ±μ 보μ₯ν μ μμ§λ§ μ΄ κ²½μ° μΈλ±μ€μ μμ λ° ν¬κΈ° μ¦κ°, ꡬνμ 볡μ‘μ±μ΄ μ¦κ°νλ λ¬Έμ λ±μ΄ λ°μνλ€.
λν Cursor κΈ°λ° λ°©μμ νλ²μ μ¬λ¬ λ°μ΄ν°λ₯Ό 건λ λ°μ΄μΌ νλ μꡬμ¬ν(ex. λΆμ°μμ μΈ νμ΄μ§ μ΄λ)μμλ μ’μ λ°©μμ΄ μλλ€. μ κ·Έλ°κ±΄μ§λ μ¬κΈ°κΉμ§ κΈμ μ½μλ€λ©΄ 곧λ°λ‘ μ΄ν΄νλ¦¬λΌ μκ°νλ€.
μμ½
- Cursor κΈ°λ° λ°©μμ Offset κΈ°λ° λ°©μμ λΉν΄ ꡬνμ΄ λ³΅μ‘νλ€.
- μ΅μ νλ Cursor κΈ°λ° νμ΄μ§λ€μ΄μ νκ²½μμλ ν μ΄λΈ λ΄ λ°μ΄ν°κ° μ무리 λ§μλ λΉ λ₯Έ μλ΅ μλλ₯Ό λ³΄μΌ μ μλ€. λν 컀μκ° μ μ°¨ λ€λ‘ κ°λλΌλ μΌμ ν μ±λ₯μ 보μ₯νλ€.
- Cursor κΈ°λ° λ°©μμμ 컀μ κ°μΌλ‘ νμ©λλ λ°μ΄ν° μ μ ν μ΄λΈ λ΄μμ μ μΌμ±μ΄ 보μ₯λμ§ μμ κ²½μ° κ²°κ³Ό μ§ν©μ μΌκ΄μ±μ 보μ₯ν μ μλ€.
- νλ²μ μ¬λ¬ λ°μ΄ν°(νμ΄μ§)λ₯Ό 건λ λ°μ΄μΌ νλ μꡬμ¬νμ΄ μ‘΄μ¬νλ€λ©΄ μ’μ μ νμ§κ° μλλ€.
μ¬λ΄
μμμ μ΄ν΄λ³Έ νμ΄μ§λ€μ΄μ κΈ°λ²λ€μ μΈμ κΉμ§λ ν μ΄λΈ μΈλ±μ€κ° μ μ νκ² κ΅¬μ±μ΄ λμ΄ μμ΄μΌ μ±λ₯ μ μ΄μ μ λ³Ό μ μλ€.
μΈλ±μ€κ° μμ΄λ 쿼리μ κ²°κ³Όμ§ν©μ΄ λ¬λΌμ§κ±°λ νμ§λ μμ§λ§ κ²°κ΅ μ λ ¬λ λ°μ΄ν°λ₯Ό κΈ°λ°μΌλ‘ λΆλΆ μ²λ¦¬λ₯Ό μννλ λ°©μμ΄κΈ° λλ¬Έμ νμν λ°μ΄ν° λ§μ DBμμ μ½κΈ° μν΄μ μ λ ¬ μμ μ 건λ λΈ μ μλ μΈλ±μ€ μ€κ³κ° νμνλ€.
λ§μ½ κ·Έλ μ§ μλ€λ©΄, λ§€λ² ν μ΄λΈ μ 체λ₯Ό νμΈν λ€ λͺ©ν λ°μ΄ν°λ₯Ό λ°λ‘ κ±Έλ¬μ£Όλ μ€ν κ³νμ΄ λμΆλκΈ° λλ¬Έμ νμ΄μ§λ€μ΄μ λμ μ ν΅ν μ±λ₯ κ°μ μ μ΄μ μ λ°λ μ μλ€.
'Database' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
λ μ½λ λλ€ μ‘°νλ₯Ό ν΅ν λκ΄μ λ½ μ±λ₯ κ°μ κΈ° (with μ¬μ΄λ νλ‘μ νΈ) (1) | 2024.05.02 |
---|---|
Database PK μμ± μ λ΅ (without DB, Mysql) (3) | 2024.03.17 |
JOINμ μ λ§ λλ¦°κ° (μμ κ·ν) (0) | 2024.01.07 |
Slow Query νμΈλ² (in Mysql, Postgresql) (0) | 2023.12.13 |