0

它不是一个设计得很好的应用程序,但它完成了工作,所以它被使用了。在过去的一周里,我一直在对其进行修改。我添加和删除了一些功能。它从 SQL 表中获取数据。根据运行情况,有时这些数据可能超过 20,000 行!

我正在考虑尝试让它一次仅将大约 500 行加载到应用程序中,因为当只有 500 行要处理时,它需要几秒钟,而不是几分钟。我正在使用 pdf,这也可能是问题的一部分,但我认为这应该不会太难实现。

问题是,我不完全确定如何实现它。我的想法是将查询限制在 0 到 500 之间,然后增加这个限制。然而,主循环检查返回的行是否为空。我怎么知道返回的行是否为空,因为它是表的最后一行而不是块的最后一行?

编辑:我很抱歉。查询很快。但是,在我对 pdf 文件执行的操作期间,这些文件本地存储在运行应用程序的文件系统上,这些操作的速度变慢了。我在想,我将 20,000 行数据拉入应用程序并让它在本地循环,这会导致速度变慢。我可能错了,但这就是我想实现分页的原因。仅在 500 行上运行程序非常快。他们都在程序开始时拉入所有行,然后使用库对 PDF 执行操作(即将此行数据放在页面上)。每行对应于 PDF 中的一个页面,因此 PDF 变得如此之大的事实也可能会减慢速度,但我会让分页工作然后报告回来。随着时间的推移,这更像是一个应用程序性能问题。

4

4 回答 4

2

由于信息有限,我只能参考一些好的 SQL 分页资源,这是开发人员非常常用的技术来限制检索的记录数量。

您可以在互联网上找到大量帖子。这是其中之一

于 2013-07-23T20:21:24.083 回答
0

哎呀。我没有仔细阅读这个问题。以下内容基于单个 PDF 存储在数据库中的错误阅读。如果没有从数据库中提取大量数据,则请忽略此答案,因为速度缓慢可能是由 PDF 生成器本身引起的,并且可以通过“注释掉添加页面”轻松验证。20k 大小合理的记录不算什么。


问题是,我不完全确定如何实现它。我的想法是将查询限制在 0 到 500 之间,然后增加这个限制。

好吧,有点(并忽略可能添加的新记录或删除的记录)。

以下是一种通用方法的步骤。(这不是唯一的方法,但我强调它是因为它是问题中提出的方法的一种变体,并解决了提到的问题。)

  1. 对数据进行排序(总是在使用视图操作时!)
  2. 使用 RDBMS 中实现的 LIMITOFFSET。如果不使用偏移量,那么 LIMIT 增加实际上是没有用的。
  3. 查询时,每个补丁 LIMIT 比期望的多一行;如果你得到 LIMIT 行,你就完成了。如果您返回 LIMIT+1 行,则需要发出另一个提取,因为有更多记录。
  4. 将 OFFSET 增加 LIMIT 并循环直到完成。

在 SQL Server 中使用OFFSET .. FETCH .. 在 ORDER BY中。

如果可以在此过程中添加/删除行,则需要考虑其他注意事项以避免幻像记录和重复记录处理。如果这样的问题是一个问题,并且可能应该是,我鼓励禁止这样的操作——即在整个循环过程中使用 SERIALIZABLE 事务——为简单起见。


分页的替代方法(实际上,20k 记录非常少)是按需加载/使用较大的“PDF”/BLOB 列以减少内存压力。使用内存不一定是坏事:但如果分配被推送到交换或热缓冲区被丢弃,它可能会对性能产生严重影响。

由于我们讨论的是 SQL Server,因此可以使用较新的FILESTREAM类型而不是 BLOB 来存储 PDF 数据。使用 FILESTREAM 列,SqlDataReader最初不会读取整个文件/流,而只会获取“文件指针”。然后,可以逐项获取基础文件

这种方法也可以用普通的 BLOB 存储和仔细选择记录(例如,在处理特定记录时只获取“PDF”/BLOB)或文件系统等外部存储(例如,只将“文件路径”存储在数据库)。

因为并非总是加载所有数据,所以使用延迟加载大型二进制/BLOB 数据的方法应该可以减轻观察到的性能影响(如果它确实与内存压力有关)并更好地扩展(尽管是一个常数因子):它在这种情况下可以完全消除分页的需要。

于 2013-07-23T20:26:35.723 回答
0

只要您的查询不再返回 500 个元素,您就可以设置一个标志,并在主循环条件中检查该标志。

于 2013-07-23T20:20:16.677 回答
0

您始终可以获取完整的键集,然后您的客户端可以通过将键集的子集传递给存储的存储过程,它可以从这些键创建一个表并进行内部连接。

于 2013-07-23T20:28:04.177 回答