【发布时间】:2016-02-02 12:02:50
【问题描述】:
我正在使用 Eclipselink、Spring Data 和 Postgresql。在我的项目中,我注意到在使用 SpringData 存储库提供的分页结果时,会出现如下查询:
SELECT COUNT(id)
FROM table
WHERE [part generated according to specification]
其中“id”是“table”的主键。用解释挖掘我注意到对于一个非常大的表, COUNT(id) 比 COUNT() 慢大约 10 倍(count(id) 在“id”列中查找非空值,而 count( ) 只返回匹配条件的行数),count(*) 也可以使用索引,而 count(id) - 不是。
我跟踪了 SpringData 基本存储库类,似乎只有 JPA 实现负责此查询生成。
- 使用 count(id) 而不是更快的 COUNT(* ) 的原因是什么?
- 我能否改变这种行为(无论如何 - 甚至增强现有组件)?
任何帮助表示赞赏
-- [编辑]--
有一张桌子:
\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 以及索引扫描与全扫描
【问题讨论】:
-
请发布执行计划 - 如果
id真的是表的主键,这很难相信。通常的神话是count(id)比count(*)快所以也许 EclipseLink 开发人员相信这个神话(我从未见过它是真的) -
在主要描述中添加了查询计划。 count(id) 如何比 count() 快(根据 w3schools:w3schools.com/sql/sql_func_count.asp) count() 只返回匹配条件的行数,而 count(id) 返回匹配条件的行数并且具有非空值。它做了一些额外的事情,所以它不能更快......也许一些特定的索引可以加速它,但不会超过 count(*) 的速度(至少我认为是这样)
-
test_order列是如何定义的?以及索引idx_test_order究竟是如何定义的?运行后计划有变化吗analyze ord_order -
test_order 只是布尔列,默认 = false (允许空值,但仅通过模式并且该列中没有空值),idx_test_order 是这一列(test_order)的简单索引,无法分析现在的表。将不得不等待维护窗口。
-
我希望来自 JPA 或 Hibernate 的人发表评论或提供解决方案。这真是一个巨大的无赖,我最近也被它击中了。
标签: java postgresql hibernate jpa spring-data-jpa