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 查询中的大结果集的主要内容,如果未能解决你的问题,请参考以下文章