java - 如何监控 JPA 和 Hibernate 执行的慢 SQL 查询

标签 java sql spring performance hibernate

我可以设置任何 Hibernate 属性来查看所有慢速查询吗?我',对返回结果集花费太多时间的查询感兴趣。

我将 Spring 与 Hibernate 结合使用,通过 applicationContext.xml Spring 配置文件进行配置。

最佳答案

hibernate 5.4

此慢速查询日志功能自 Hibernate ORM 5.4.5 起可用,并会在给定 JPQL、Criteria API 或 native SQL 查询的执行时间超过您之前配置的特定阈值时通知您。

配置

为了激活 Hibernate 慢查询日志,您需要将 hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS 属性设置为大于 0 的值,表示查询执行阈值。

在我们的例子中,任何超过 25 毫秒的查询都将触发 Hibernate 慢速查询日志。

Spring Boot 配置

如果您使用的是 Spring Boot,则可以在 application.properties 配置文件中设置此 Hibernate 设置:

spring.jpa.properties.hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS=25

Java EE 配置

如果您使用的是 Java EE,则可以在 persistence.xml 配置文件中进行设置:

<property
    name="hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS"
    value="25"
/>

记录器配置

您还需要至少将 org.hibernate.SQL_SLOW 记录器设置为 INFO 级别。

如果你正在使用 Logback,你可以按如下方式设置它:

<logger name="org.hibernate.SQL_SLOW" level="info"/>

就是这样!

测试时间

假设我们在应用程序中定义了以下 Post 实体类:

Post entity class

Post 实体映射如下:

@Entity(name = "Post")
@Table(name = "post")
public class Post {
 
    @Id
    private Long id;
 
    private String title;
 
    @Column(name = "created_on")
    @CreationTimestamp
    private Date createdOn;
 
    @Column(name = "created_by")
    private String createdBy;
 
    //Getters and setters omitted for brevity
}

我们将保留 5000 个 Post 实体,以便我们有足够的数据来生成需要超过 25 毫秒的查询:

LongStream
.rangeClosed(1, 5000)
.forEach(i -> {
    entityManager.persist(
        new Post()
        .setId(i)
        .setTitle(
            String.format(
                "High-Performance Java Persistence book - page %d review",
                i
            )
        )
        .setCreatedBy("Vlad Mihalcea")
    );
     
    if(i % 50 == 0 && i > 0) {
        entityManager.flush();
    }
});

检测慢速 JPQL 查询

执行以下 JPQL 查询时:

List<Post> posts = entityManager
.createQuery(
    "select p " +
    "from Post p " +
    "where lower(title) like :titlePattern " +
    "order by p.createdOn desc", Post.class)
.setParameter(
    "titlePattern", 
    "%Java%book%review%".toLowerCase()
)
.setFirstResult(1000)
.setMaxResults(100)
.getResultList();

Hibernate 生成以下慢查询日志条目:

o.h.SQL_SLOW -
    SlowQuery: 32 milliseconds.
    SQL:
    'PgPreparedStatement [
        select
            p.id as id1_0_,
            p.created_by as created_2_0_,
            p.created_on as created_3_0_,
            p.title as title4_0_
        from
            post p
        where lower(p.title) like '%java%book%review%'
        order by p.created_on desc
        limit 100
        offset 1000
    ]'

检测缓慢的 Criteria API 查询

执行此 Criteria API 查询时:

CriteriaBuilder builder = entityManager
    .getCriteriaBuilder();
 
CriteriaQuery<Post> postQuery = builder
    .createQuery(Post.class);
     
Root<Post> post = postQuery.from(Post.class);
 
postQuery
    .where(
        builder.like(
            builder.lower(post.get("title")),
            "%Java%book%review%".toLowerCase()
        )
    )
    .orderBy(
        builder.desc(post.get("createdOn"))
    );
 
List<Post> posts = entityManager.createQuery(
    postQuery
)
.setFirstResult(1000)
.setMaxResults(100)
.getResultList();

Hibernate 生成一个慢查询日志条目,如下所示:

o.h.SQL_SLOW -
    SlowQuery: 27 milliseconds.
    SQL: 'PgPreparedStatement [
        select
            p.id as id1_0_,
            p.created_by as created_2_0_,
            p.created_on as created_3_0_,
            p.title as title4_0_
        from
            post p
        where
            lower(p.title) like '%java%book%review%'
        order by p.created_on desc
        limit 100
        offset 1000
    ]'

检测慢速 native SQL 查询

List<Post> posts = entityManager
.createNativeQuery(
    "SELECT p.* " +
    "FROM post p " +
    "WHERE LOWER(p.title) LIKE :titlePattern " +
    "ORDER BY p.created_on DESC", Post.class)
.setParameter(
    "titlePattern",
    "%Java%book%review%".toLowerCase()
)
.setFirstResult(1000)
.setMaxResults(100)
.getResultList();

我们得到一条由 Hibernate 编写的慢查询日志消息:

o.h.SQL_SLOW -
    SlowQuery: 27 milliseconds.
    SQL: 'PgPreparedStatement [
        SELECT
            p.*
        FROM post
            p
        WHERE
            LOWER(p.title) LIKE '%java%book%review%'
        ORDER BY p.created_on DESC
        LIMIT 100
        OFFSET 1000
    ]'

In our case, the application query type doesn't influence the slow query log since both JPQL and Criteria API generate SQL queries that are similar to the native SQL one we used in the last test case.

关于java - 如何监控 JPA 和 Hibernate 执行的慢 SQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3349344/

相关文章:

spring - 如何在 Spring Boot 应用程序中使用禁用连接池?

java - 将jar包封装成dll

java - Spring MVC Double 的默认值

java - 为什么在方法内声明的变量如果要在同一方法内定义的内部类中使用,则需要将其声明为final?

sql - 如何使用 Sequel 运行原始 SQL 查询

java - @Autowired 不在构造函数中创建成员

java - @exceptionhandler 不在 Spring REST 中工作

Java - 将指向对象的指针传递给函数

java - 无法从oracle 11g数据库读取表

MySQL:A列和B列累计和到B列