存储结果集以供以后获取

Posted

技术标签:

【中文标题】存储结果集以供以后获取【英文标题】:Storing result set for later fetch 【发布时间】:2011-05-06 06:53:15 【问题描述】:

我有一些查询会运行很长时间(20-30 分钟)。如果同时启动大量查询,连接池很快就会耗尽。

是否可以将长时间运行的查询包装到一个语句(过程)中,将通用查询的结果存储到临时表中,终止连接,并在以后按需获取(轮询)结果?

编辑: 查询和数据结构已优化,“检查您的索引和执行计划”之类的提示对我不起作用。我正在寻找一种方法来存储 [也许是] 通用结果集的字节表示,以供以后检索。

【问题讨论】:

您也可以发布您的查询,我敢打赌这里的一些专家可以加快速度。 我不是在寻找优化一两个查询的方法。 可以增加连接数吗? @jonearles 连接池容量 ATM 是 50。我可以增加它,但考虑到大多数连接是空闲的,我宁愿轮询结果集而不是等待查询完成。 这些查询是如何执行的?通过您无法控制的应用程序,还是仅由您控制?如果这些只是您执行的查询,JOTN 的“create table as select”解决方案应该可以工作。 【参考方案1】:

首先,20-30 分钟对于查询来说是非常长的时间 - 你确定你没有遗漏任何查询索引吗?请检查您的执行计划 - 您可以从放置良好的索引中获得巨大的性能提升。

mysql 中,你可以这样做

INSERT INTO `cached_result_table` (
    SELECT your_query_here
)

(当然,cached_result_table 的列结构必须与您的SELECT 返回的列结构完全相同,否则会报错)。

然后,您可以查询这些缓存的结果(而不是原始表),并且只不时运行上述查询 - 以更新 cached_result_table。

当然,查询最初至少需要运行一次,这将需要您提到的 20-30 分钟。我建议在请求数据之前预先填充缓存表,并保留一些锁定机制以防止更新查询同时运行多次。伪代码:

init:
insert select your_big_query

work:
if your_big_query cached table is empty or nearing expiration:
  refresh in the background:
     check flag to see if there's another "refresh" process running
     if yes
       end // don't run two your_big_queries at the same time
     else 
       set flag
       re-run your_big_query, save to cached table
       clear flag
serve data to clients always from cached table

【讨论】:

"...顺便说一句,20-30 分钟是相当长的时间 - 你确定你没有错过任何查询索引吗?..." - +1 就是为了这个。跨度> @duffymo:我已将此通知移至开头。这是常识,但有时会被忽视。 @Piskvor 谢谢提示! 1.所有查询都经过优化(数据端复杂性太大(-> 电​​信提供商的客户端使用统计信息)- 这就是 20-30 分钟的来源)。 2.有没有可能概括你的方法,这样我就不必为每个查询创建一个表,而是存储结果集的字节表示,或者类似的东西。 @Dave:这么想 - 电信公司往往会生成大量数据。至于存储结果集,AFAIK 你必须在数据库之外进行那种缓存——在这种情况下 MySQL 对你没有多大帮助。 我们在生产中使用 Oracle。添加 mysql 标记很讨厌 - 我只是想拥有尽可能多的专业知识 :) 结果集的缓存不是我想要实现的主要目标。我想要做的是释放等待查询完成的阻塞客户端套接字,并稍后按需设置计算结果(缓存只是一个额外的酷选项)。到目前为止,@Vasil Remeniuk 提出的解决方案对我来说是最有趣的。【参考方案2】:

在 Oracle 中执行此操作的一个简单方法是“CREATE TABLE sometempname AS SELECT...”。这将使用来自选择的结果列创建一个新表。

【讨论】:

创建的表是否会填充结果集中的数据? 是的,它将包含数据。【参考方案3】:

我能想到的 Oracle 中最通用的方法是创建一个存储过程,它将结果集转换为 XML,并将其作为 CLOB XMLType 存储在一个包含长时间运行查询结果的表中。

您可以找到更多关于从通用结果集 here 生成 XML。

SQL> select dbms_xmlgen.getxml('select employee_id, first_name,
  2  last_name, phone_number from employees where rownum < 6') xml
  3  from dual

【讨论】:

为什么?您认为为每个要存储的结果集结构创建一个新表更好吗?【参考方案4】:

不太清楚你的要求。

目前您有 50 个数据库会话。假设您有 40 个正在运行的长时间运行的查询,剩下 10 个可以为其余的提供服务。

您似乎要求的是,您希望这 40 个查询异步(在后台运行)不会阻塞 50 个连接池。问题是,您是否希望这 40 个查询与(可能)另外 50 个同时运行来自连接池的查询,还是您希望它们以某种方式排队?

可以进行排队(查看 DBMS_SCHEDULER 和 DBMS_JOB)。但是您需要将这些结果传递到其他表中,并知道如何传递该结果集。老式的方法只是根据请求生成报告,然后将其发送到共享驱动器上的目录或通过电子邮件发送。可以是 PDF、CSV 或 Excel。

如果您希望 40 个与 50 个“连接池”设置同时运行,那么您最好为长时间运行的查询设置一个单独的连接池。

您可以查看资源管理器以终止占用时间过长或资源过多的调用。这样,快速池就不会陷入长时间运行的请求中。

【讨论】:

我在 JDBC 中有一个包含 50 个连接的池 - 我用来从 Java 连接到数据库的驱动程序。 JDBC为每个数据库连接创建一个VM线程(在幕后,连接是一个阻塞的客户端套接字),我想要实现的是在即发即弃模式下处理长时间运行的查询,释放线程/connection 在将队列推送到数据库之后立即获取结果集。 所以,如果我理解正确,您的问题是客户端的连接数已达到 50 个,但数据库仍有容量。

以上是关于存储结果集以供以后获取的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django 会话中存储查询集以进行分页

如何从两个不同的 Laravel 查询构建器中获取我的两个结果集以同时显示在同一页面上?

Django:保存旧的查询集以供将来比较

公开大型 Web 服务数据集以供 Access 或 Excel 使用

如何转换结果集以使列值成为聚合标题?

将 Cloud Storage 文件转换为 BigQuery 表/数据集以供稍后查询