【问题标题】:Run long Oracle stored procedure from PHP从 PHP 运行长 Oracle 存储过程
【发布时间】:2018-04-23 17:58:59
【问题描述】:

我有一个从 PHP 运行的存储过程:

//Request does not change
$sql = 'BEGIN SP_GET_MY_DATA(:POP, :SEG, :DUR, :VIEW, :PAGE, :OUTPUT_CUR); END;';            

//Statement does not change
$stmt = oci_parse($conn,$sql);                     
oci_bind_by_name($stmt,':POP',$pop);           
oci_bind_by_name($stmt,':SEG',$seg);           
oci_bind_by_name($stmt,':DUR',$dur);           
oci_bind_by_name($stmt,':VIEW',$view);           
oci_bind_by_name($stmt,':PAGE',$page);    

//But BEFORE statement, Create your cursor
$cursor = oci_new_cursor($conn)

// On your code add the latest parameter to bind the cursor resource to the Oracle argument
oci_bind_by_name($stmt,":OUTPUT_CUR", $cursor,-1,OCI_B_CURSOR);

// Execute the statement as in your first try
oci_execute($stmt);

// and now, execute the cursor
oci_execute($cursor);

// Use OCIFetchinto in the same way as you would with SELECT
while ($data = oci_fetch_assoc($cursor, OCI_RETURN_LOBS )) {
    print_r($data}
}

问题是我在存储过程中有数百万行和复杂的逻辑。当我通过 SQL 开发人员执行 SP_GET_MY_DATA 时,大约需要 2 个小时才能完成。

当我这样做时,PHP 正在超时。我也无法增加 PHP 中的 max_execution_time。

如何在 Oracle 上运行它或使用 PHP 而不会超时?请帮忙。

【问题讨论】:

  • 使用 DBMS_SCHEDULER oracle 包将其作为程序运行
  • @OldProgrammer - 你能给我一个同样的例子吗?
  • 没有。谷歌“oracle dbms_scheduler”并阅读文档。

标签: php oracle stored-procedures


【解决方案1】:

我在 DBA 堆栈交换的这个答案中非常全面地回答了如何使用 Oracle Scheduler 异步运行长时间运行的过程。见https://dba.stackexchange.com/a/67913/38772

TL;DR 是

-- submit this as a background job
BEGIN
  dbms_scheduler.create_job ( 
      job_name => 'MY_BACKGROUND_JOB'
    , job_type => 'STORED_PROCEDURE'    
    , job_action => 'SP_GET_MY_DATA'
    , enabled => TRUE
    , auto_drop => TRUE
  );
END;

如果您想将参数传递给过程,您将不得不做更多的工作。你可能会发现这个答案很有帮助https://dba.stackexchange.com/q/42119/38772/

有关所有血腥细节的更多参考,Oracle 文档中的相关章节位于https://docs.oracle.com/database/121/ADMIN/scheduse.htm

【讨论】:

  • 这很棒。但是,如果我希望 DBMS_Scheduler 顺序运行作业,我该怎么做?我不想因为很多请求而使我的 Oracle 服务器过载。
  • @dang,如果您有几个要串行执行的存储过程,您可以编写一个新的存储过程,它只是按顺序调用您的其他存储过程,基本上我称之为包装过程。然后你让调度器作业调用这个新过程。
  • Joshua - 啊,我的意思是 - 假设我将通过 PHP 调用 10 个不同的存储过程,然后 15 个用户访问这 10 个调用,所以我将在 DBMS_Scheduler 中创建 150 个工作.如果我有 150 个作业,我的 Oracle 服务器会变慢。我想知道的是 - 我可以按顺序运行作业吗?也就是说,Oracle 不是并行运行所有 150 个作业,而是一次处理一个作业,处理它,然后处理下一个作业。
  • @dang,在这种情况下,听起来你需要一个队列。 Oracle 确实有一个高级队列特性 (AQ),但我一直觉得它有点复杂。使用数据库表作为队列很诱人,但很多人会警告您不要这样做——请参阅mikehadlow.blogspot.com/2012/04/…softwareengineering.stackexchange.com/questions/231410/…。这将是使用 RabbitMQ 或 ZeroMQ 作为排队解决方案的一个很好的案例。您甚至可以使用 PHP(或任何语言)来实现队列工作者。
【解决方案2】:

不要增加max_execution_time,设置为0,让它无限运行。如果要返回大量行,请确保增加内存 (ini_set) 或允许立即刷新缓冲区,以便它可以直接输出到客户端。

后者还将防止客户端因为没有获得任何数据而过早断开连接。 (ob_implicit_flush(true);)

【讨论】:

  • 感谢您的回答,但不会导致内存问题吗?
  • 如果你隐式刷新,那么不会。输出立即发送到客户端,而不是保存在输出缓冲区中(即,在脚本完全完成之前发送输出),连同 fetch_assoc 它实际上内存非常低,但是客户端将接收所有行,所以这可能会在客户端填满。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-21
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多