如何提高JPA/PostgreSQL查询性能?

如何提高JPA/PostgreSQL查询性能?,postgresql,performance,spring-data-jpa,Postgresql,Performance,Spring Data Jpa,我有一个表,有3664万个条目。 表定义如下: id integer, PK attribute, varchar 255 value, varchar 255 store_id, integer timestamp, timestamp without timezone mac_address, varchar 255 另外,mac_地址和时间戳列具有索引 查询: select count(*) from table where mac_address = $1 and timestamp

我有一个表,有3664万个条目。 表定义如下:

id integer, PK
attribute, varchar 255
value, varchar 255
store_id, integer
timestamp, timestamp without timezone
mac_address, varchar 255
另外,mac_地址和时间戳列具有索引

查询:

select count(*) from table where mac_address = $1 and timestamp between $2 and $3
select * from table where mac_address = $1 and timestamp between $2 and $3
如果我在pgAdmin中运行这个程序,总共需要10秒。 如果我用JPA运行这个程序,需要40多秒。没有急切的装载

我已经研究过SimpleParepository代码。正是这两个查询,一个count和一个getResultList

问题: 1.pgAdmin和JPA中似乎都没有使用时间戳索引。我已经用分析和解释检查过了。但是为什么呢? 2.为什么JPA需要更多10倍的时间?ORM增加了开销,但增加了10倍? 3.我如何改进它

编辑1:

也许JPA的计数没有使用索引扫描,而是使用sequential=slow。我的postgresql版本是9.5

编辑2: 在JPA中,它使用setFirstResult和setMaxResult获得总共100个条目。从总数259242

我试着用LIMIT和OFFSET来模拟它,但我在JPA查询中没有看到这些关键字。也许JPA得到了所有结果,然后在内存中进行分页,这反过来会导致性能问题

使用pgAdmin第一次执行count查询需要19到55秒

这两个问题的解释

计数

挑选

Limit  (cost=3362.52..5043.49 rows=100 width=34) (actual time=30.291..42.846 rows=100 loops=1)
  Output: id, attributecode, attributevalue, mac_address, store_id, "timestamp"
  Buffers: shared hit=15447 read=1676"
  ->  Index Scan Backward using device_messages_pkey on public.device_messages playerstat0_  (cost=0.57..5759855.56 rows=342650 width=34) (actual time=2.597..42.834 rows=300 loops=1)
        Output: id, attributecode, attributevalue, mac_address, store_id, "timestamp"
        Filter: ((playerstat0_."timestamp" >= '2018-04-04 00:00:00'::timestamp without time zone) AND (playerstat0_."timestamp" <= '2018-05-04 00:00:00'::timestamp without time zone) AND ((playerstat0_.mac_address)::text = '0011E004CA34'::text))
        Rows Removed by Filter: 154833
        Buffers: shared hit=15447 read=1676
Planning time: 0.180 ms
Execution time: 42.878 ms
编辑3: 经过进一步测试,确认原因为计数。使用限制和偏移进行选择非常快。单是伯爵一个人就要花上一分钟。 这里提到

虽然count estimate函数在查询计划中处理行,但我无法从JPA中调用它

编辑3: 我有点解决了这个问题,但还没有完全解决

关于select,在创建与查询匹配的索引之后,它实际上运行得相当快,2~5秒。但这是没有分类的。排序将另一个过程步骤添加到查询中

计数缓慢,并由postgresql文档确认。MVCC强制计数执行堆扫描,类似于对整个表进行序列扫描


最后一个问题是,我仍然不能确定生产服务器上的查询速度比测试服务器慢多少。60秒用于生产,5秒用于测试服务器。具有相同的表大小和数据。但最大的区别是生产服务器每秒有20多个插入操作。测试服务器没有正在进行的插入操作。我猜插入操作可能需要一个写锁,因此查询速度很慢,因为它必须等待锁?

如果在同一索引中同时使用mac\U地址和时间戳索引,您应该能够获得更好的性能:

在表mac_地址、时间戳上[并发]创建索引

不使用时间戳索引的原因是,它需要将时间戳索引与mac_地址索引交叉引用,以找到正确的行,这实际上比直接查找行需要更长的时间


我没有JPA的经验,所以我真的说不出为什么它慢。

1。你有多少张唱片?2.你是怎么多得到10倍的时间的?我怀疑您正在获取大量数据,并且您正在比较JPA中的实际检索与不获取某些SQL客户端中的所有数据的SQL执行。不使用时间戳索引的一个原因可能与它使用的索引类型有关。它是b树还是散列索引?其他数据库管理系统也可以根据基于数据统计计算的成本来决定使用哪个索引。这可能是原因reason@AdrianShum我想你是对的,在我向下滚动之前,pgAdmin可能不会读取所有记录,所以速度要快得多。我使用的是默认的B树索引。请回答您的问题并添加使用explain analyze、buffers生成的执行计划。请问,那张表上到底有哪些索引?这是mac_地址、时间戳的组合索引还是两个单列索引?查询返回多少行?也许这只是一个简单的例子,JPA花了太长时间来处理一个大的结果。
Limit  (cost=3362.52..5043.49 rows=100 width=34) (actual time=30.291..42.846 rows=100 loops=1)
  Output: id, attributecode, attributevalue, mac_address, store_id, "timestamp"
  Buffers: shared hit=15447 read=1676"
  ->  Index Scan Backward using device_messages_pkey on public.device_messages playerstat0_  (cost=0.57..5759855.56 rows=342650 width=34) (actual time=2.597..42.834 rows=300 loops=1)
        Output: id, attributecode, attributevalue, mac_address, store_id, "timestamp"
        Filter: ((playerstat0_."timestamp" >= '2018-04-04 00:00:00'::timestamp without time zone) AND (playerstat0_."timestamp" <= '2018-05-04 00:00:00'::timestamp without time zone) AND ((playerstat0_.mac_address)::text = '0011E004CA34'::text))
        Rows Removed by Filter: 154833
        Buffers: shared hit=15447 read=1676
Planning time: 0.180 ms
Execution time: 42.878 ms