java - eclipselink jpa 使用 COUNT(id) 而不是 COUNT(*) 生成计数查询

标签 java postgresql hibernate jpa spring-data-jpa

我正在使用 Eclipselink、Spring Data 和 Postgresql。在我的项目中,我注意到当使用 SpringData 存储库提供的分页结果时,会出现如下查询:

SELECT COUNT(id) 
FROM table 
WHERE [part generated according to specification]

其中“id”是“表”的主键。通过解释挖掘,我注意到对于一个非常大的表,COUNT(id) 比 COUNT() 慢大约 10 倍(count(id) 在“id”列中查找非空值,而 count( ) 只返回匹配条件的行数),也 count(* ) 可以使用索引,而 count(id) 则不能。

我跟踪了 SpringData 基本存储库类,似乎只有 JPA 实现负责此查询生成。

  1. 使用 count(id) 而不是更快的 COUNT(* ) 的原因是什么?
  2. 我能否改变这种行为(无论如何 - 甚至增强现有组件)?

感谢任何帮助

-- [编辑] --

有一张 table :

\d ord_order
                                       Table "public.ord_order"
         Column          |           Type            |                       Modificators
-------------------------+--------------------------+----------------------------------------------------------
 id                      | integer                  | NOT NULL DEFAULT nextval('ord_order_id_seq'::regclass)
 test_order              | boolean                  | DEFAULT false
...
Indexes:
    "pk_order" PRIMARY KEY, btree (id)
    "idx_test_order" btree (test_order)



# explain SELECT COUNT(*) FROM ord_order WHERE (test_order = false);
                                QUERY PLAN
--------------------------------------------------------------------------
 Aggregate  (cost=89898.79..89898.80 rows=1 width=0)
   ->  Index Only Scan using idx_test_order on ord_order  (cost=0.43..85375.37 rows=1809366 width=0)
         Index Cond: (test_order = false)
         Filter: (NOT test_order)
(4 wiersze)



# explain SELECT COUNT(id) FROM ord_order WHERE (test_order = false);
                                QUERY PLAN
--------------------------------------------------------------------------
 Aggregate  (cost=712924.52..712924.53 rows=1 width=4)
   ->  Seq Scan on ord_order  (cost=0.00..708401.10 rows=1809366 width=4)
         Filter: (NOT test_order)
(3 wiersze)

现在区别是 ~90k 与 ~713k 以及索引扫描与全扫描

最佳答案

我设法提供自定义 Spring Data Repository 基类实现和使用该实现的工厂。结果生成的计数查询现在具有以下形式:

SELECT COUNT(1) FROM table

与 COUNT(* ) 具有相同的计划。这似乎是一个很好的解决方案,并且适用于应用程序中所有定义的存储库。

我不知道如何生成 COUNT(* ),COUNT(1) 更容易,因为 COUNT 函数需要一些表达式作为参数,而且我可以提供静态值 - 1

关于java - eclipselink jpa 使用 COUNT(id) 而不是 COUNT(*) 生成计数查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33480424/

相关文章:

C libpq : get float value from numeric

java - 为什么 Hibernate @OneToOne 执行多个选择查询而不是一个?

java - 在 Spring Data JPA 中使用 @Transactional 注解的层

java - 如何使用 Softlayer API 订购公共(public)和私有(private) Vlan

sql - jsonb_array_elements 获取元素位置

java - Android - 从 assets\PDF 显示访问文件

json - Postgresql 9.4 - 转换为 JSONB 时输入语法无效

java - NoClassDefinitionFoundError 发现javax/transaction/TransactionManager

java - 如何提示用户仅输入他们可以选择的三个选项之一,并在输入错误时显示错误消息

java - JavaFX 中是否有功能允许您单击超链接并在 Chrome 或 Firefox 等浏览器中打开它?