← Назад к вопросам

Как профилировал запросы

3.0 Senior🔥 71 комментариев
#JVM и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как профилировал запросы

Профилирование запросов — это процесс анализа производительности кода и базы данных, чтобы найти узкие места.

Инструмент 1: Логирование SQL с Hibernate

spring:
  jpa:
    properties:
      hibernate:
        format_sql: true
        generate_statistics: true
logging:
  level:
    org.hibernate.SQL: DEBUG

Это покажет все SQL запросы с временем выполнения.

Инструмент 2: JProfiler

Один из лучших профайлеров для Java. Показывает:

  • CPU время по методам
  • Потребление памяти
  • Вызовы между методами
java -agentpath=/path/to/jprofiler/bin/libjprofilerti.so -jar myapp.jar

Инструмент 3: Java Flight Recorder

Безопасен для production, минимальный оверхед.

java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder \
     -XX:StartFlightRecording=filename=recording.jfr -jar myapp.jar

Инструмент 4: P6Spy для логирования SQL

<dependency>
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>3.9.1</version>
</dependency>

Вывод: Показывает все SQL запросы с временем выполнения

Инструмент 5: Spring Boot Actuator

@Service
public class UserService {
    @Timed(value = "user.fetch")
    public User findById(Long id) {
        return repository.findById(id);
    }
}

Доступно по: GET /actuator/metrics/user.fetch

Инструмент 6: EXPLAIN ANALYZE в PostgreSQL

EXPLAIN ANALYZE
SELECT u.id, u.name FROM users u WHERE u.status = 'ACTIVE';

Покажет:

  • Используется ли индекс
  • Реальное время выполнения
  • Количество прочитанных строк

Практический пример

@Service
public class ProfiledService {
    @Autowired
    private UserRepository repository;
    
    public List<User> findActiveUsers() {
        long start = System.currentTimeMillis();
        List<User> users = repository.findByStatus(UserStatus.ACTIVE);
        long elapsed = System.currentTimeMillis() - start;
        
        logger.info("Query took {}ms", elapsed);
        return users;
    }
}

Инструмент 7: curl для HTTP анализа

curl -w "Total: %{time_total}ms" http://localhost:8080/api/users

Инструмент 8: Hibernate Statistics

Statistics stats = ((SessionFactoryImpl)emf).getStatistics();
stats.setStatisticsEnabled(true);
System.out.println("Entity Loads: " + stats.getEntityLoadCount());
System.out.println("Prepared Statements: " + stats.getPreparedStatementCount());

Лучшие практики профилирования

  1. Меряй в реалистичных условиях — с реальными данными
  2. Повторяй несколько раз — избегай погрешностей
  3. Профилируй hot spots — фокусируйся на медленных методах
  4. Сравнивай до/после — убедись что улучшение сработало
  5. Используй sampling — 100% профилирование замедляет приложение
  6. Ищи N+1 проблемы — частая причина медленных запросов
  7. Добавляй индексы — обычно дает 50% прирост
  8. Кэшируй результаты — для часто используемых данных

Типичные находки при профилировании

  • N+1 SELECT: один запрос за каждого пользователя вместо одного
  • Отсутствие индексов на часто фильтруемых полях
  • Загрузка в памяти миллионов записей без пагинации
  • Неправильные JOIN'ы вместо более эффективных запросов
  • Кэширование для каждого запроса без TTL

Профилирование — это постоянный процесс поиска и устранения узких мест. Начинай с логирования, потом добавляй инструменты по мере необходимости.