hibernate看慢查询

时间:2010-07-28 01:51:50

标签: java sql hibernate spring

在hibernate.property中。是我可以设置任何参数查看所有慢速查询,花费太多时间返回结果?我正在使用spring-hibernate applicationContext.xml

4 个答案:

答案 0 :(得分:10)

由于这是一个非常常见的问题,所以我写了 this article,此答案基于此。

休眠5.4

此慢查询日志功能自Hibernate ORM 5.4.5开始提供,并在给定JPQL,Criteria API或本机SQL查询的执行时间超过您先前配置的某个阈值时通知您。

配置

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

在我们的情况下,任何花费超过25毫秒的查询都会触发Hibernate慢速查询日志。

Spring Boot配置

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

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实体类:

<code>Post</code> 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
    ]'

检测慢速本机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
    ]'

在我们的案例中,应用程序查询类型不会影响慢查询日志,因为JPQL和Criteria API都会生成与我们在上一个测试案例中使用的本机SQL相似的SQL查询。

答案 1 :(得分:4)

我有2条建议:

  • 您可以使用Oracle的Statspack。
  • 您可以使用某种JDBC代理驱动程序记录执行时间P6Spylog4jdbc

过去我使用了来自IronGrid的P6Spy和IronTrack SQL,这是一个不错的组合(参见this blog post)。但请注意:

  • P6Spy并未真正维护(5年没有变更)。
  • 这些措施并不完全准确(追逐贪吃猪时这不是一个大问题。)
  • IronTrack SQL似乎不再可用(但您仍然可以找到它,例如here)。

我个人正在使用log4jdbc现在提供类似的功能(没有花哨的GUI,但他们关心,使用Excel或他们提供的脚本来生成报告)。从其网站:

  

功能

     
      
  • 完全支持JDBC 3和JDBC 4!
  •   
  • 易于配置,在大多数情况下,您只需更改驱动程序即可   班级名称   net.sf.log4jdbc.DriverSpy和prepend   “jdbc:log4”到你现有的jdbc网址,   设置您的日志记录类别和   你准备好了!
  •   
  • 在记录的输出中,对于预准备语句,绑定参数是   自动插入SQL   输出。这大大改善了   许多人的可读性和调试性   例。
  •   
  • 可以生成SQL计时信息以帮助确定多长时间   SQL语句需要运行,有助于   识别正在运行的语句   太慢了,这个数据可以发布   使用附带的工具处理   生成分析报告数据   快速识别你的慢速SQL   应用即可。
  •   
  • 生成SQL连接编号信息以帮助识别连接   汇集或线程问题。
  •   
  • 使用JDK 1.4及更高版本的任何底层JDBC驱动程序   SLF4J 1.x。
  •   
  • 开源软件,在业务友好的Apache 2.0下获得许可   执照:   http://www.apache.org/licenses/LICENSE-2.0
  •   

答案 2 :(得分:2)

您可以通过将hibernate.show_sql属性设置为true来启用hibernate中所有SQL的日志记录(请参阅http://www.javalobby.org/java/forums/t44119.html)。但是,无法过滤以仅查看慢速查询。但是,如果您使用的是mysql,则可以启用其慢查询日志,并查看速度低于设置阈值的查询。

请参阅:http://adminlinux.blogspot.com/2009/07/mysql-slow-queries-log.html

我确信大多数其他数据库都会提供类似的功能。

答案 3 :(得分:0)

这是added natively in Hibernate 5.4.5.Final。配置参数位于AvailableSettings.LOG_SLOW_QUERY

说明是:

  

设置日志记录查询的执行速度比指定时间慢   毫秒。默认值为0(禁用)。