반응형

개념

파티셔닝(Partitioning)이란?

  • 하나의 데이터베이스 안에서 여러 파티션으로 나눠 데이터를 관리하여 성능 최적화와 관리 효율성을 높이는 방식을 말한다.
  • 쿼리 성능 향상 및 데이터 관리 최적화를 위해 사용한다.
  • 장점
    • 쿼리 수행시 특정 파티션에만 접근하므로 쿼리 성능이 향상된다.
    • 데이터 아카이빙 및 데이터 파기 등에 유용하다.
    • 단일 데이터베이스를 관리하기 때문에 비교적 관리하기 쉽다.
  • 단점
    • 물리적으로 같은 데이터베이스 내에 존재하기 때문에 확장성은 제한적이다.
    • 특정 쿼리가 여러 파티션에 걸쳐야할 경우 성능이 저하될 수 있다.

파티셔닝 종류

  • RANGE 파티셔닝 : 연속적인 값 범위에 따라 데이터를 분리. ex) 날짜 범위별
  • LIST 파티셔닝 : 특정 값 목록에 따라 데이터를 분리. ex) 지역별
  • HASH 파티셔닝 : 해시 함수를 사용하여 데이터를 고르게 분산시켜 분리. 균등한 데이터 분포를 보장함

예제

MySQL 실행

docker-compose.yml

version: "3.3"
services:
  mysql01:
    image: mysql:9.0.1
    ports:
      - "13306:3306"
    environment:
      TZ: Asia/Seoul
      MYSQL_DATABASE: test
      MYSQL_ROOT_PASSWORD: 123456
    command:
      - "--character-set-server=utf8mb4"
      - "--collation-server=utf8mb4_unicode_ci"

실행

docker-compose up -d

테이블 생성

CREATE TABLE Message
(
    id        CHAR(36),
    sender    VARCHAR(100),
    receiver  VARCHAR(100),
    title     VARCHAR(100),
    contents  VARCHAR(500),
    createdAt DATETIME(3) NOT NULL,
    PRIMARY KEY (id, createdAt) -- 파티션키는 기본키에 포함되어야함
)
PARTITION BY RANGE (TO_DAYS(createdAt)) (
    PARTITION p_202408 VALUES LESS THAN (TO_DAYS('2024-09-01')),
    PARTITION p_202409 VALUES LESS THAN (TO_DAYS('2024-10-01')),
    PARTITION p_202410 VALUES LESS THAN (TO_DAYS('2024-11-01'))
);

application.yml

spring:
  datasource:
    hikari:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:13306/test
      username: root
      password: 123456

  jpa:
    open-in-view: false
    properties:
      hibernate:
        hbm2ddl:
          auto: none
        show_sql: true
        format_sql: false
        use_sql_comments: false
        implicit_naming_strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
        physical_naming_strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

logging:
  level:
    org.hibernate.orm.jdbc.bind: trace

Message

@IdClass(Message.PrimaryKey::class)
@Entity
data class Message(
    @Id
    val id: String,
    val sender: String,
    val receiver: String,
    var title: String,
    var contents: String,
    @Id
    val createdAt: LocalDateTime,
) {
    data class PrimaryKey(
        val id: String = UUID.randomUUID().toString(),
        val createdAt: LocalDateTime = LocalDateTime.now(),
    ) : Serializable
}

MessageRepository

@Repository
interface MessageRepository : JpaRepository<Message, Message.PrimaryKey> {
    fun findByCreatedAtGreaterThanEqualAndCreatedAtLessThan(startAt: LocalDateTime, endAt: LocalDateTime): List<Message>
}

MessageTest

@SpringBootTest
class MessageTest {
    @Autowired
    private lateinit var messageRepository: MessageRepository

    private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")

    @Test
    fun test() {
        messageRepository.save(Message(UUID.randomUUID().toString(), "tyler-1", "john-1", "title-1", "contents-1", LocalDateTime.parse("2024-08-05 00:00:00", formatter)))
        messageRepository.save(Message(UUID.randomUUID().toString(), "tyler-2", "john-2", "title-2", "contents-2", LocalDateTime.parse("2024-08-06 00:00:00", formatter)))
        messageRepository.save(Message(UUID.randomUUID().toString(), "tyler-3", "john-3", "title-3", "contents-3", LocalDateTime.parse("2024-08-30 00:00:00", formatter)))
        messageRepository.save(Message(UUID.randomUUID().toString(), "tyler-4", "john-4", "title-4", "contents-4", LocalDateTime.parse("2024-09-05 00:00:00", formatter)))
        messageRepository.save(Message(UUID.randomUUID().toString(), "tyler-5", "john-5", "title-5", "contents-5", LocalDateTime.parse("2024-10-05 00:00:00", formatter)))

        // id, createdAt 복합키가 기본키이기 때문에 update 쿼리의 where 조건에도 id, createdAt가 모두 추가됨. createdAt 기반으로 특정 파티션을 찾아 쿼리 수행
        val message = messageRepository.findByCreatedAtGreaterThanEqualAndCreatedAtLessThan(LocalDateTime.parse("2024-09-01 00:00:00", formatter), LocalDateTime.parse("2024-10-01 00:00:00", formatter))
        messageRepository.save(message.first().copy(title = "title-22"))

        val message1 = messageRepository.findByCreatedAtGreaterThanEqualAndCreatedAtLessThan(LocalDateTime.parse("2024-08-05 00:00:00", formatter), LocalDateTime.parse("2024-08-06 00:00:00", formatter)).first()
        val message2 = messageRepository.findByCreatedAtGreaterThanEqualAndCreatedAtLessThan(LocalDateTime.parse("2024-09-01 00:00:00", formatter), LocalDateTime.parse("2024-10-01 00:00:00", formatter)).first()

        assertEquals("title-1", message1.title)
        assertEquals("title-22", message2.title)
    }
}
반응형

+ Recent posts