Skip to content

can019/mysql-primary-key

Repository files navigation

Summary

JPA를 이용한 MySQL PK 성능 테스트 및 테스트 수행 속도 개선

MySQL PK 성능 테스트

Core concept

Insertion test

sequenceDiagram
    participant InsertTest
    participant StopWatch
    participant EntityManager
    participant Database

    loop "For loop or repeated test..."
        InsertTest->>InsertTest: create entity instance
        InsertTest->>StopWatch: start
        activate StopWatch
        InsertTest->>EntityManager: persist(entity)
        activate EntityManager
        EntityManager->>EntityManager: persist entity
        EntityManager->>Database: commit
        deactivate EntityManager
        Database-->>EntityManager: committed
        EntityManager-->>InsertTest: committed
        InsertTest->>StopWatch: stop
        deactivate StopWatch
    end
Loading
  • 쓰기 지연이 아닌 즉시 commit이 일어나야 함
  • 선언적 transactional 적용 시 주의

Reports

1000 times (Single thread)

테스트 수행 속도 개선

  1. N threads per method + for loop (n=3, 15 thread)
    • n = ForkJoinPool thread 개수 / Test method 개수
    • test 환경 n = 15 / 5 = 3
  2. Thread per method + for loop (5 thread)
  3. Single thread (1 thread)

총 수행 시간 측정 방법

TestExecutionListenersDefaultTestTimeExecutionListener를 추가

DefaultTestTimeExecutionListener

sequenceDiagram
    actor Junit
    participant DefaultTestTimeExecutionListener
    participant StopWatch
    participant Test Class
    
    Junit ->>+ DefaultTestTimeExecutionListener: beforeTest
        DefaultTestTimeExecutionListener ->>+ StopWatch: start
            StopWatch -->>+ StopWatch: : start
    DefaultTestTimeExecutionListener -->>- Junit: notify

    Junit ->>+ Test Class: execute beforeAll
        Test Class ->> Test Class: Run beforeAll
    Test Class -->>- Junit: notify
    
    Junit ->>+ Test Class: execute test method
        Test Class ->> Test Class: Run test method
    Test Class -->>- Junit: notify

    Junit -->>+ Test Class: execute afterAll
        Test Class -->> Test Class:  Run afterAll
    Test Class -->>- Junit: notify

    Junit ->>+ DefaultTestTimeExecutionListener: afterTest
         DefaultTestTimeExecutionListener ->> StopWatch: stop
         StopWatch -->>- StopWatch: : stop
    DefaultTestTimeExecutionListener ->> DefaultTestTimeExecutionListener: pretty print StopWatch
    DefaultTestTimeExecutionListener -->>- Junit: notify
Loading

N threads per method + for loop

  • Concurrency로 설정 후 RepeatedTest시 repeatedTime 마다 서로 다른 thread에서 수행되는 것을 이용
    • @ReapeatedTest(value)에 할당하고자 하는 thread 개수 기입
    • 원하는 insertion 개수 / @ReapeatedTest(value) 만큼 for-loop의 iteration 기입
  • 각 thread에서 호출되는 insertionTest끼리 순서를 알 수 없음
    • 어떤 entity가 먼저 삽입될지 알 수 없음
    • persist 시간 역시 측정 대상이므로 StopWatch의 task name으로 pk를 지정 불가
    • PK와 TaskInfo를 key - value로 map에 넣음
    • entity에는 created at column 추가, 해당 정보는 database에서 insert 시점에 작성하도록 함
  • Thread local map 에 넣은 후 iteration이 끝나면 ConcurrentMap에 putAll
    • ConcurrentMap에 각 iteration마다 Pk-task mapping 정보 삽입 시 lock이 걸려 성능 저하가 발생할 것이라고 예상
    • for-loop 안에서 thread local map에 넣어두었다가 loop가 끝나면 ConcurrentMap에 putAll
  • OrderBy createdAt으로 읽어 온 후 해당 list를 순회하며 ConcurrentMap에서 해당 pk에 대한 TaskInfo를 가져옴
    • Taskinfo에서 nanoSecond 정보를 가져와 csv 작성

Rough concept

@RepeatedTest(value = N = 2)

  • 원하는 insert time이 100, n=2인 경우 loop iteration = 100 / 2 = 50
sequenceDiagram
    actor Junit
    participant PrimaryKeyPerformanceTestMultiThreadV2
    participant  PrimaryKeyPerformanceTestInternal
    par
        par repeated test for method 1 
            Junit ->>+ PrimaryKeyPerformanceTestMultiThreadV2: Execute test method 1
                PrimaryKeyPerformanceTestMultiThreadV2 ->> PrimaryKeyPerformanceTestMultiThreadV2: insertTest
                    loop: Measure time and save mapping info 
                        PrimaryKeyPerformanceTestMultiThreadV2 ->>+ PrimaryKeyPerformanceTestInternal: persisAndGetEntity
                        PrimaryKeyPerformanceTestInternal -->>- PrimaryKeyPerformanceTestMultiThreadV2: 
                    end
            PrimaryKeyPerformanceTestMultiThreadV2-->>- Junit: notify
        and
            Junit ->>+ PrimaryKeyPerformanceTestMultiThreadV2: Execute test method 1
                PrimaryKeyPerformanceTestMultiThreadV2 ->> PrimaryKeyPerformanceTestMultiThreadV2: insertTest
                    loop: Measure time and save mapping info
PrimaryKeyPerformanceTestMultiThreadV2 ->>+ PrimaryKeyPerformanceTestInternal: persisAndGetEntity
                        PrimaryKeyPerformanceTestInternal -->>- PrimaryKeyPerformanceTestMultiThreadV2: 
                    end
            PrimaryKeyPerformanceTestMultiThreadV2-->>- Junit: notify
        end
        
        par repeated test for method 2
            Junit ->>+ PrimaryKeyPerformanceTestMultiThreadV2: Execute test method 2
                PrimaryKeyPerformanceTestMultiThreadV2 ->> PrimaryKeyPerformanceTestMultiThreadV2: insertTest
                loop: Measure time and save mapping info
PrimaryKeyPerformanceTestMultiThreadV2 ->>+ PrimaryKeyPerformanceTestInternal: persisAndGetEntity
                    PrimaryKeyPerformanceTestInternal -->>- PrimaryKeyPerformanceTestMultiThreadV2: 
                end                                                     
            PrimaryKeyPerformanceTestMultiThreadV2-->>- Junit: notify
        and
            Junit ->>+ PrimaryKeyPerformanceTestMultiThreadV2: Execute test method 1
                PrimaryKeyPerformanceTestMultiThreadV2 ->> PrimaryKeyPerformanceTestMultiThreadV2: insertTest
                loop: Measure time and save mapping info
PrimaryKeyPerformanceTestMultiThreadV2 ->>+ PrimaryKeyPerformanceTestInternal: persisAndGetEntity
                    PrimaryKeyPerformanceTestInternal -->>- PrimaryKeyPerformanceTestMultiThreadV2: 
                end
            PrimaryKeyPerformanceTestMultiThreadV2-->>- Junit: notify
        end
    end
Loading

Measure time and save mapping info

sequenceDiagram
    participant InsertTest
    participant Thread local StopWatch
    participant PrimaryKeyTestMultiThreadInternal
    participant Database
    participant Root ConcurrentMap
    participant ConcurrentMap

    InsertTest->> Root ConcurrentMap: get ConcurrentMap("entity class type")
    Root ConcurrentMap->> InsertTest: return ConcurrentMap("entity class type")
    InsertTest->> Thread local StopWatch: get StopWatch
    Thread local StopWatch->> InsertTest: return StopWatch
loop "Measure time and save mapping info"
        InsertTest->>InsertTest: create entity instance
        InsertTest->>Thread local StopWatch: start
        activate Thread local StopWatch
        InsertTest->>PrimaryKeyTestMultiThreadInternal: persist(entity)
        activate PrimaryKeyTestMultiThreadInternal
        PrimaryKeyTestMultiThreadInternal->>PrimaryKeyTestMultiThreadInternal: persist entity
        PrimaryKeyTestMultiThreadInternal->>Database: commit
        deactivate PrimaryKeyTestMultiThreadInternal
        Database-->>PrimaryKeyTestMultiThreadInternal: committed
        PrimaryKeyTestMultiThreadInternal-->>InsertTest: committed
        InsertTest->>Thread local StopWatch: stop
        deactivate Thread local StopWatch
        
        activate InsertTest
        InsertTest->> InsertTest: ThreadLocal map.put(entity.getId(), stopWatch.getLastTaskInfo());
        deactivate InsertTest
    end
    InsertTest->>+ ConcurrentMap: ConcurrentMap("entity class type").putAll(map)
    ConcurrentMap ->> ConcurrentMap: putAll
    ConcurrentMap ->>- InsertTest: 
Loading

Line graph

Efficiency ratio(time)

Thread efficiency

Detail

ERD

v0 (Single thread, Thread per method + for loop)

erDiagram
jpa_auto_increment {
bigint id PK
}
jpa_sequence {
bigint id PK
}
uuidv1_with_created_at {
binary(16) id PK
}
uuidv4_with_created_at {
binary(16) id PK
}
uuidv1_sequential_with_created_at {
binary(16) id PK
}
Loading

v1 (N threads per method + for loop)

erDiagram
jpa_auto_increment_with_created_at {
  bigint id PK 
  timestamp(6) created_at
}
jpa_sequence_with_created_at {
  bigint id PK
  timestamp(6) created_at
}
uuidv1_with_created_at {
  binary(16) id PK
  timestamp(6) created_at
}
uuidv4_with_created_at {
  binary(16) id PK
  timestamp(6) created_at
}
uuidv1_sequential_with_created_at {
  binary(16) id PK
  timestamp(6) created_at
}

Loading

Common

Description

  • created_at:

    Default: CURRENT_TIMESTAMP(6)

    Extra: DEFAULT_GENERATED

    Null: YES

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages