【问题标题】:Multithreaded Delphi database application failing with large amounts of data多线程 Delphi 数据库应用程序因大量数据而失败
【发布时间】:2011-07-06 16:54:44
【问题描述】:

应用概述:
我有一个 Delphi 应用程序,它允许用户定义多个查询,并在多个 MySQL 数据库上同时运行它们。一次可以运行的线程数有限制(用户可以设置)。用户选择要运行的查询,以及要在其上运行查询的系统。每个线程使用 TADOQuery 组件在指定系统上运行指定查询。

问题描述:
当查询检索到少量记录时,应用程序工作正常,即使提交了大量线程(最多约 100 个)。只要一次只运行几个线程(最多约 8 个),该应用程序还可以处理大量记录(150,000+)。但是,当用户一次运​​行大约 10 个以上的查询(即 10+ 个线程),并且每个线程正在检索大约 150,000+ 条记录时,我们开始出现错误。以下是我们目前遇到的具体错误信息:

一个:Not enough storage is available to complete this operation
乙:OLE error 80040E05
c:Unspecified error
d:线程创建错误:Not enough storage is available to process this command
邮箱:Object was open
女:ODBC Driver does not support the requested properties

显然,错误是由多种因素造成的:线程数、每个线程检索的数据量,以及可能的 MySQL 服务器配置。

真正的主要问题是为什么会发生错误?我很欣赏它似乎在某种程度上与资源相关,但鉴于返回的错误不同,我想弄清楚错误出现的确切原因。是PC上的资源问题,还是与服务器的配置有关。

接下来的问题是我们可以做些什么来避免出现问题?我们目前正在通过减少可以并发运行的线程数来限制应用程序。我们不能强迫用户检索更少的记录,因为查询完全是用户定义的,如果他们想要检索 200,000 条记录,那么这取决于他们,所以我们在这方面无能为力。实际上,我们不想降低应用程序的速度,因为大多数用户将检索少量数据,我们不想让应用程序变慢以供他们使用,尽管线程数可以由用户更改,我们宁愿找到问题的根源并尝试修复它,而不必一直依赖于调整配置。

【问题讨论】:

  • 你可以设置TADOQuery.CursorType := ctOpenForwardOnly吗?它可能有助于资源分配。
  • 你能告诉我们用于设置线程、连接和查询的代码吗?

标签: mysql sql multithreading delphi


【解决方案1】:

看起来您正在客户端加载大量数据。它们可能需要缓存在客户端内存中(特别是如果您使用双向游标),并且在 32 位应用程序中可能还不够,这取决于平均行大小和库存储行的效率。 通常,完成数据库工作的最佳方式是直接在服务器上执行,而无需将数据检索到客户端。通常数据库有一个高效的缓存系统,当它们不适合内存时可以将数据写入磁盘。 为什么一次检索 150000 行?您可以使用一种机制仅在用户实际访问数据时才传输数据(通过数据进行分页),以避免大量“浪费”内存。

【讨论】:

  • 据我了解,数据量少线程数没问题:The application can ... handle larger numbers of records (150,000+) as long as only a few threads (up to about 8) are running at once.
  • 这很明显。线程共享其进程的地址空间。创建的线程越多,每个线程可用的内存空间就越少。
  • 我一直在寻找关于究竟是什么导致错误的具体内容,因为我的经理要求我提供具体细节。但是,我对他关于正在使用的线程数以及每个线程检索的数据量的回应似乎是根本原因,所以我对这个答案很满意。仅供参考,在某些情况下,我们需要检索大量数据,以便可以在 PC 上存档报告并稍后离线解析。但是,我相信检索机制可以更有效,因此我将对此进行研究。感谢您的回复。
  • 如果您需要在本地存储数据,您应该避免将整个记录集缓存在内存中。使用单向、非缓存游标(检查 ADO 游标选项)读取它,并将其存储在磁盘上。通常,直接使用 DB 库并利用任何有用的特定功能可以更好地处理此类情况,使用 ADO 在很大程度上取决于提供程序的质量及其实现的功能 - 如果您使用 OLEDB-ODBC 桥,它可能会更糟;) 但是正确设置 ODBC 和 ADO 无论如何它都可以工作。
  • DevArt (devart.com/mydac, 商业) 是一个允许直接访问 MySQL 的 Delphi 库,但我几乎没有使用过一次,不能保证它可以轻松解决您的问题。也可能有一些操作系统库。如果 32 位进程内存是一个问题并且机器有 4GB+ 内存,您可以尝试使用 /3GB 开关(并启用 LARGE_ADDRESS_AWARE PE 标志)作为权宜之计,或者生成新进程而不是线程(每个 32 位进程可以使用 2/3GB 的 RAM,在 64 位操作系统下最多 4 个)。使用 ADO,尝试使用服务器端的只进游标。查看 MSDN 上的 ADO 文档。
【解决方案2】:

这很有意义(您遇到问题的事实,而不是具体错误)。想一想 - 你有 10 个数据库连接(每个线程 1 个),每个连接通过单个网络连接接收 150,000 行数据(总共 1,500,000 行)。即使您不使用客户端游标并且行很小(只有几个小列),这也是跨单个网络接口的巨大数据流,并且对客户端计算机上的内存造成很大影响。

我怀疑错误消息不正确,就像有时您在另一个代码位置发生内存覆盖导致访问冲突一样。

【讨论】:

    【解决方案3】:

    根据您的 DBMS,为了帮助解决问题,您可以使用 LIMIT/TOP sql 子句来限制返回的数据量。

    【讨论】:

      【解决方案4】:

      我会做的事情:

      • 编写一个非常简单的测试应用程序,它只使用连接/查询创建的必要部分(使用线程),这将消除软件其他部分引起的所有副作用

      • 使用不同的数据库访问层而不是 ODBC,以确定 ODBC 驱动程序是否是问题的根本原因

      • 看起来当线程数较少时内存使用没有问题 - 为了验证这一点,我还将测量/计算记录的内存需求,将其与应用程序的内存使用情况进行比较操作系统。例如,如果测试表明 4 个线程可以安全地查询 1.5 GB 的总数据而没有问题,但 10 个线程在总数据不足 0.5 GB 时失败,我会说这是一个线程问题

      【讨论】:

        猜你喜欢
        • 2013-11-24
        • 2013-02-04
        • 1970-01-01
        • 2014-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-02
        • 2019-04-01
        相关资源
        最近更新 更多