Newer
Older
pivot-app / src / main / java / ru / mcs / service / BenchmarkService.java
package ru.mcs.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import ru.mcs.dto.BenchmarkResult;
import ru.mcs.entity.MtObject;
import ru.mcs.repository.MtDataRepository;

@Service
@RequiredArgsConstructor
@Slf4j
public class BenchmarkService {

    private final DataGeneratorService generatorService;
    private final NativeBatchInsertService nativeBatchService;
    private final MetadataService metadataService;
    private final MtDataRepository dataRepository;

    public BenchmarkResult runInsertBenchmark(Integer orgId, String objectName, int recordCount) {
        MtObject obj = metadataService.getObjectByName(orgId, objectName);

        log.info("Starting INSERT benchmark (JPA): count={}", recordCount);

        long startTime = System.currentTimeMillis();
        int generated = generatorService.generateData(orgId, obj.getObjId(), recordCount);
        long durationMs = System.currentTimeMillis() - startTime;

        return BenchmarkResult.builder()
                .operation("INSERT_JPA")
                .objectName(objectName)
                .recordCount(generated)
                .durationMs(durationMs)
                .recordsPerSecond((double) generated * 1000 / durationMs)
                .build();
    }

    public BenchmarkResult runNativeInsertBenchmark(Integer orgId, String objectName, int recordCount) {
        MtObject obj = metadataService.getObjectByName(orgId, objectName);

        log.info("Starting INSERT benchmark (Native): count={}", recordCount);

        try {
            long startTime = System.currentTimeMillis();
            int generated = nativeBatchService.batchInsert(orgId, obj.getObjId(), recordCount, 5000);
            long durationMs = System.currentTimeMillis() - startTime;

            return BenchmarkResult.builder()
                    .operation("INSERT_NATIVE")
                    .objectName(objectName)
                    .recordCount(generated)
                    .durationMs(durationMs)
                    .recordsPerSecond((double) generated * 1000 / durationMs)
                    .build();
        } catch (Exception e) {
            log.error("Native insert failed", e);
            throw new RuntimeException(e);
        }
    }

    public BenchmarkResult runSelectBenchmark(Integer orgId, String objectName, int iterations) {
        MtObject obj = metadataService.getObjectByName(orgId, objectName);

        log.info("Starting SELECT benchmark: iterations={}", iterations);

        // Warmup с пагинацией
        for (int i = 0; i < 3; i++) {
            dataRepository.findByOrgIdAndObjIdPaged(orgId, obj.getObjId(), PageRequest.of(0, 1000));
        }

        long totalRecords = dataRepository.countByOrgIdAndObjId(orgId, obj.getObjId());

        // Тест SELECT с LIMIT 1000
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < iterations; i++) {
            dataRepository.findByOrgIdAndObjIdPaged(orgId, obj.getObjId(), PageRequest.of(0, 1000));
        }
        long durationMs = System.currentTimeMillis() - startTime;
        long avgDuration = durationMs / iterations;

        return BenchmarkResult.builder()
                .operation("SELECT_PAGED_1000")
                .objectName(objectName)
                .recordCount((int) totalRecords)
                .durationMs(avgDuration)
                .recordsPerSecond(avgDuration > 0 ? 1000.0 * 1000 / avgDuration : 0)
                .iterations(iterations)
                .build();
    }

    public BenchmarkResult runCountBenchmark(Integer orgId, String objectName, int iterations) {
        MtObject obj = metadataService.getObjectByName(orgId, objectName);

        log.info("Starting COUNT benchmark: iterations={}", iterations);

        // Warmup
        for (int i = 0; i < 3; i++) {
            dataRepository.countByOrgIdAndObjId(orgId, obj.getObjId());
        }

        long startTime = System.currentTimeMillis();
        long count = 0;
        for (int i = 0; i < iterations; i++) {
            count = dataRepository.countByOrgIdAndObjId(orgId, obj.getObjId());
        }
        long durationMs = System.currentTimeMillis() - startTime;
        long avgDuration = durationMs / iterations;

        return BenchmarkResult.builder()
                .operation("COUNT")
                .objectName(objectName)
                .recordCount((int) count)
                .durationMs(avgDuration)
                .iterations(iterations)
                .build();
    }

    public long getRecordCount(Integer orgId, String objectName) {
        MtObject obj = metadataService.getObjectByName(orgId, objectName);
        return dataRepository.countByOrgIdAndObjId(orgId, obj.getObjId());
    }

    public BenchmarkResult runLightweightSelectBenchmark(Integer orgId, String objectName, int iterations) {
        MtObject obj = metadataService.getObjectByName(orgId, objectName);

        // Warmup
        for (int i = 0; i < 3; i++) {
            dataRepository.findLightweight(orgId, obj.getObjId(), 1000);
        }

        long startTime = System.currentTimeMillis();
        int rows = 0;
        for (int i = 0; i < iterations; i++) {
            rows = dataRepository.findLightweight(orgId, obj.getObjId(), 1000).size();
        }
        long durationMs = System.currentTimeMillis() - startTime;
        long avgDuration = durationMs / iterations;

        return BenchmarkResult.builder()
                .operation("SELECT_NATIVE_1000")
                .objectName(objectName)
                .recordCount(rows)
                .durationMs(avgDuration)
                .recordsPerSecond(avgDuration > 0 ? (double) rows * 1000 / avgDuration : 0)
                .iterations(iterations)
                .build();
    }
}