postgresql 查询中的大结果集

Posted

技术标签:

【中文标题】postgresql 查询中的大结果集【英文标题】:Large ResultSet on postgresql query 【发布时间】:2010-10-24 01:11:09 【问题描述】:

我正在对 postgresql 数据库中的表运行查询。数据库位于远程计算机上。该表有大约 30 个使用 postgresql partitioning capability 的子表。

查询将返回一个大的结果集,大约 180 万行。

在我的代码中,我使用 spring jdbc 支持,方法 JdbcTemplate.query,但我的 RowCallbackHandler 没有被调用。

我的最佳猜测是 postgresql jdbc 驱动程序(我使用版本 8.3-603.jdbc4)在调用我的代码之前将结果累积到内存中。我以为fetchSize configuration 可以控制这个,但我试过了,没有任何改变。我这样做是作为 postgresql 手册recomended。

当我使用 Oracle XE 时,此查询运行良好。但是我正在尝试迁移到 postgresql,因为分区功能在 Oracle XE 中不可用。

我的环境:

PostgreSQL 8.3 Windows Server 2008 企业版 64 位 JRE 1.6 64 位 春季 2.5.6 Postgresql JDBC 驱动程序 8.3-603

【问题讨论】:

您的电话回了吗?如果没有,您是否尝试过 ctrl-\(Windows 的 ctrl-break)、jstack、jconsole、visualvm 或类似工具来查找线程停止的位置? 它在驱动程序内部处理查询。 另见***.com/a/47517489/32453 【参考方案1】:

为了使用游标检索数据,您必须设置 ResultSet.TYPE_FORWARD_ONLY 的 ResultSet 类型(默认值)并自动提交为 false,此外还要设置获取大小。这在您链接到的文档中被引用,但您没有明确提及您执行了这些步骤。

小心 PostgreSQL 的分区方案。它确实对优化器做了非常可怕的事情,并且可能会导致不应该出现的大量性能问题(取决于您的数据的具体情况)。无论如何,您的行只有 180 万行吗?鉴于它已被适当索引,没有理由仅根据大小对其进行分区。

【讨论】:

是的,我完成了文档中描述的所有步骤(TYPE_FORWARD_ONLY 和 autocommit false)。 1.8M 是我目前的样品。数据按天分区,每个分区一天。每天大约有 40 万行。 恐怕我帮不上忙。我对 pg JDBC 驱动程序和多 GB 分析查询的获取大小没有任何问题,但我没有使用 spring 库的经验。就像测试一样,我会尝试不分区。您期望数据集增长到多大?每天 400k 行,我不希望您当前的算法持续那么久。在不完全了解您的用例的情况下,我建议您开始研究星型模式和数据维度等数据仓库技术。 感谢特雷的帮助。我正在存储历史市场数据。我将使用 30 天的数据。这就像一个 30 天的滑动窗口,从今天到 30 天前。每天都会修改继承以链接新分区和取消链接旧分区。数据将存在一年左右,但在给定时间只会链接 30 个子表(天)。正在使用分区来使这种维护更加可行。【参考方案2】:

我敢打赌,您的应用程序中没有一个客户端同时需要 180 万行。您应该想出一种明智的方法,将结果分成更小的部分,并让用户有机会迭代它们。

这就是谷歌所做的。当您进行搜索时,可能会有数百万次点击,但它们一次会返回 25 页,并认为您会在第一页找到您想要的内容。

如果它不是客户端,并且正在以某种方式处理结果,我建议让数据库处理所有这些行并简单地返回结果。仅仅为了在中间层进行计算而返回 180 万行是没有意义的。

如果这两个都不适用,那么您就遇到了真正的问题。是时候重新考虑了。

在阅读了后面的回复后,我觉得这更像是一种报告解决方案,应该批量处理或实时计算并存储在不属于您的事务系统的表中。将 180 万行带到计算移动平均线的中间层是无法扩展的。

我建议重新定位自己 - 开始将其视为一种报告解决方案。

【讨论】:

数据库加载在系统启动时完成一次,以按摩数据并将其“转换”为更适合客户使用的格式。 RowCallbackHandler 本身无需配置任何内容。但是很多关于连接、数据源、驱动或者数据库设计的配置。在海量数据所在的生产服务器上调试它有点困难。我只有日志记录。【参考方案3】:

fetchSize 属性按照postgres manual 中的描述工作。

我的错误是我将 auto commit = false 设置为来自连接池的连接,该连接不是准备好的语句正在使用的连接。

感谢所有反馈。

【讨论】:

【参考方案4】:

我做了上面的所有事情,但我需要最后一点:确保调用被包装在事务中并将事务设置为只读,这样就不需要回滚状态。

我添加了这个:@Transactional(readOnly = true)

干杯。

【讨论】:

以上是关于postgresql 查询中的大结果集的主要内容,如果未能解决你的问题,请参考以下文章

将时间戳与查询中的日期名称相等,并在 PostgreSQL 查询中获取结果集 w.r.t 日期名称

索引扫描不适用于 postgres 中的 json 数据集

PostgreSQL & JDBC“查询返回了多个结果集”

Postgresql的使用

Postgres:具有(延迟)读写访问权限的大表

识别 RDS 上 Postgresql 的慢查询