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();
}
}