2012-02-15 97 views
4

我一直在注意Postgres(8.3)中简单聚合性能的一些问题。问题是,如果我有一个由(customer_id,order_id)唯一的表(比如200M行),那么查询select customer_id,max(order_id) from larger_table group by customer_id比执行以下操作的简单Java/JDBC程序慢一个数量级以上:postgres综合性能

1)初始化一个空的HashMap的customerMap(这将映射id - > max order size) 2)执行“select customer_id,order_id from larger_table”,并获得一个流结果集3)迭代遍历结果集排如下所示:

long id = resultSet.getLong("customer_id"); 
long order = resultSet.getLong("order_id"); 
if (!customerMap.containsKey(id)) 
    customerMap.put(id,order); 
else 
    customerMap.put(id,Math.max(order,customerMap.get(id))); 

预计这种性能差异?我不应该这样想,因为我认为上述内容与内部发生的事情非常接近。它是否有证据表明db有错误/不正确的调整?

+3

请在您的声明中包含“EXPLAIN ANALYZE”的输出,以便我们看看您是否缺少索引。 – 2012-02-15 05:17:13

回答

6

这可能是您的work_mem设置太低。我会先检查一下。最近我被这个问题困住了。第二个最可能的问题是您缺少外键索引。

展览如下。

一般来说,有需要问每当数据库性能看起来低于标准杆的几个问题:

  1. 您是否使用了最新版本? 7.4和9.0之间的每个版本都会带来显着的性能提升 - 如果可以升级,建议使用。
  2. 您是否在真实数据上运行您的基准测试? PostgreSQL的查询计划程序将在同一张表上生成不同的计划,其中包含不同的数据或不同数量的数据。确保你总是用真实的数据进行测试。
  3. 你的PostgreSQL配置是什么样的? work_mem设置开箱即用,我自己遇到涉及GROUP BY的情况,在这种情况下人为地选择了错误的计划,因为它根本不认为它有足够的工作内存来对结果进行排序。
  4. 是您的Java代码与数据库运行在同一台机器上?如果没有,你可能会看到计算机之间的差异,而不是方法之间的差异。
  5. 你错过了什么索引? PostgreSQL不会自动为外键创建索引,只是主键。我也被这个咬了,但如果你谷歌周围你可以找到一个脚本,将检测并添加缺少的外键索引。

没有检查查询计划,再次猜测PostgreSQL为给定查询选择了什么实现策略并不是一个好主意。

+2

'work_mem'的补充:与JVM默认分配的内存相比,缺省设置是非常低的。如果Java可以将所有的'(customer,max_order_id)'元组保留在内存中,但是PostgreSQL不会......这将是一个不公平的游戏。 ;-) – 2012-02-15 19:34:42

+2

工作内容竟然是罪魁祸首!谢谢 – ryan 2012-02-18 07:37:12