【问题标题】:How to improve select query speed on Spring with Hibernate and PostgreSQL?如何使用 Hibernate 和 PostgreSQL 在 Spring 上提高选择查询速度?
【发布时间】:2018-09-05 21:02:14
【问题描述】:

我最近设法在 VPS 上部署了一个 Spring Boot 项目。当我的机器上几乎立即运行的选择查询减慢到爬行速度时,我感到非常惊讶。我知道它会慢一些,只是没想到这么多。

我创建了一个重现该问题的测试项目。它从包含 100 000 行的表中选择大约 20 000 行。创建查询大约需要 100 微秒,运行查询大约需要 0.5-2 秒。我尝试使用 10 倍以上的行进行测试,但花费的时间比这要长得多,最终抛出了 OutOfMemoryError

我四处搜索,似乎不应该花这么长时间,特别是因为在我看来数据并不多。我阅读并了解了索引,但即使是一个应该是索引使用的好例子的查询也需要很多时间。直接在psql 控制台中运行查询大约需要 100 毫秒(没有索引)和 20 毫秒。

如果您想对其进行测试,请下载serverclient 项目并按照那里的说明进行操作。我从我的真实项目开始,尽可能多地删除了一些东西,但留下了相似之处,以便进行比较。


我的 VPS 规格:

2×2,4 GHz CPU

2 GB 内存

uname -a
Linux ampix 2.6.32-042stab127.2 #1 SMP Thu Jan 4 16:41:44 MSK 2018 x86_64 GNU/Linux

Debian 杰西

Java 8 x64

PostgreSQL 9.4

Spring Boot 2.0.1.RELEASE


提前致谢。

更新 1:忘记写 Spring 之外的测试,忘记了我在选择条件中使用 0,8 而不是 0,9,所以选择的行数大于我的最初写的。

更新 2:使用返回 Stream<> 的派生查询将性能提高了可以忽略不计的数量。

【问题讨论】:

    标签: postgresql spring-boot spring-data-jpa


    【解决方案1】:

    您可能会用完 RAM,尤其是只有 2GB 的内存。我没有在 Postgres 服务器上分析您的查询,但我会先尝试两件事:

    1. 首先,修复您的查询(尤其是对于这样的简单查询)以使用派生的 Spring Data JPA 查询甚至是 Spring Data JPQL 查询:

      public interface ScaleTestRepository extends CrudRepository<ScaleTest, Integer>, ScaleTestRepositoryCustom {
      
          // This is a derived query
          List<ScaleTest> findByWhereTest(BigDecimal whereTest);
      
      }
      
      // Or do...
      
      public interface ScaleTestRepository extends CrudRepository<ScaleTest, Integer>, ScaleTestRepositoryCustom {
      
          // This is a derived query
          @Query("select scaleTest from ScaleTest as scaleTest where where_test > ?")
          List<ScaleTest> findByWhereTest(BigDecimal whereTest);
      
      }
      

    以上内容将让 Spring JPA 为您派生查询,然后您可以利用以下内容。

    1. 其次,使用StreamFlux 作为返回类型:

      Stream<ScaleTest> findByWhereTest(BigDecimal whereTest);
      
      // Or do
      
      Flux<ScaleTest> findByWhereTest(BigDecimal whereTest);
      

      其中任何一个都将流式传输(通过 ResultSet 的零碎),这样您就不会将所有这些数据拉入内存并耗尽您的 RAM。

    【讨论】:

    • 我试过了。在我提供的测试项目中,几乎比第一个版本花费了一半的时间。不过,我想相信至少可以达到一个数量级的改进。相同的解决方案在主项目中几乎没有什么不同。哦,我在第一篇文章中添加了缺失的信息。
    • 在 Postgres 中运行相同的查询需要多长时间?您是否对该查询运行了EXPLAIN 以查看查询计划的外观,看看它是否正在执行任何意外的表扫描?在我们开始讨论 Java 之前,我们应该首先确保它不是 SQL 瓶颈。
    • 100 毫秒没有索引,20 毫秒有。我之前使用过EXPLAIN,发现它正在使用索引,但由于某种原因它现在没有使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-29
    • 1970-01-01
    相关资源
    最近更新 更多