2009-10-06 50 views
5

Có thể có các đầu ra từ PL/SQL trong thời gian thực không? Tôi có một gói phần mềm khá lớn chạy hơn một giờ và tôi muốn xem gói hàng ở đâu vào thời điểm cụ thể.Có các đầu ra PL/SQL trong thời gian thực

Dù sao, tôi hiện làm điều này với một bảng đăng nhập, được lấp đầy với hàng trăm mô tả nhật ký mỗi lần chạy, tôi chỉ tò mò nếu điều này là có thể.

Cảm ơn!

Trả lời

8

Tôi không biết nếu điều này là chính xác những gì bạn muốn nhưng tôi sử dụng dbms_application_info.set_module để xem nơi gói của tôi là.

dbms_application_info.set_module(module_name => 'Conversion job', 
           action_name => 'updating table_x'); 

Truy vấn trên v$session sẽ cho bạn biết phần nào của quy trình đang chạy.

+1

Được chọn để đơn giản. – jonasespelita

4

bạn có thể sử dụng autonomous transactions (như được đề xuất trong ví dụ this SO).

Điều này sẽ cho phép bạn viết và cam kết trong bảng nhật ký mà không cần thực hiện giao dịch chính. Sau đó bạn sẽ có thể làm theo những gì xảy ra trong kịch bản chính của bạn trong khi nó đang chạy (tình cờ, nó cũng sẽ cho phép bạn thời gian/điều chỉnh lô của bạn).

+0

+1 Ngoài ra còn có một mô tả tốt trong "Oracle PL/SQLProgramming" của Feuerstein, cũng có sẵn trong các cuốn sách của Google. – Thorsten

+0

Rất tuyệt! Tôi đã học được một điều mới ngày hôm nay. :) – jonasespelita

8

Đây là loại điều tôi sử dụng (đầu ra có thể được nhìn thấy trong v $ session và v $ session_longops) ...

DECLARE 
    lv_module_name VARCHAR2(48); 
    lv_action_name VARCHAR2(32); 

    gc_MODULE CONSTANT VARCHAR2(48) := 'MY_PROC'; 

    -- For LONGOPS 
    lv_rindex BINARY_INTEGER; 
    lv_slno BINARY_INTEGER; 

    lc_OP_NAME CONSTANT VARCHAR2(64) := '['||gc_MODULE||']'; 
    lv_sofar NUMBER; 

    -- This is a guess as to the amount of work we will do 
    lv_totalwork NUMBER; 
    lc_TARGET_DESC CONSTANT VARCHAR2(64) := 'Tables'; 
    lc_UNITS CONSTANT VARCHAR2(64) := 'Rows'; 

    CURSOR tab_cur 
    IS 
     SELECT owner, table_name 
     FROM all_tables; 

BEGIN 
    <<initialisation>> 
    BEGIN 
     -- To preserve the calling stack, read the current module and action 
     DBMS_APPLICATION_INFO.READ_MODULE(module_name => lv_module_name 
             , action_name => lv_action_name); 

     -- Set our current module and action 
     DBMS_APPLICATION_INFO.SET_MODULE(module_name => gc_MODULE 
             , action_name => NULL); 
    END initialisation; 

    <<main>> 
    BEGIN 
     DBMS_APPLICATION_INFO.SET_ACTION(action_name => 'Part 01'); 
     NULL; 

     DBMS_APPLICATION_INFO.SET_ACTION(action_name => 'Part 02'); 
     FOR tab_rec IN tab_cur 
     LOOP 
     DBMS_APPLICATION_INFO.SET_CLIENT_INFO(client_info => 'Rows = ['||TO_CHAR(tab_cur%ROWCOUNT, '999,999,999')||']'); 
     NULL; 
     END LOOP; 

     DBMS_APPLICATION_INFO.SET_ACTION(action_name => 'Part 03'); 

     --Initialising longops 
     lv_rindex := DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS_NOHINT; 
     lv_sofar := 0; 
     lv_totalwork := 5000; -- This is a guess, but could be actual if the query is quick 

     FOR tab_rec IN tab_cur 
     LOOP 
     DBMS_APPLICATION_INFO.SET_CLIENT_INFO(client_info => 'Rows = ['||TO_CHAR(tab_cur%ROWCOUNT, '999,999,999')||']'); 

     lv_sofar := lv_sofar + 1; 

     -- Update our totalwork guess 
     IF lv_sofar > lv_totalwork 
     THEN 
      lv_totalwork := lv_totalwork + 500; 
     END IF; 

     DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(rindex  => lv_rindex 
                , slno  => lv_slno 
                , op_name  => lc_OP_NAME 
                , sofar  => lv_sofar 
                , totalwork => lv_totalwork 
                , target_desc => lc_TARGET_DESC 
                , units  => lc_UNITS 
               ); 
     END LOOP; 

     -- Clean up longops 
     DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS(rindex  => lv_rindex 
               , slno  => lv_slno 
               , op_name  => lc_OP_NAME 
               , sofar  => lv_sofar 
               , totalwork => lv_sofar 
               , target_desc => lc_TARGET_DESC 
               , units  => lc_UNITS 
               ); 
    END main; 

    <<finalisation>> 
    BEGIN 
     -- Reset the module and action to the values that may have called us 
     DBMS_APPLICATION_INFO.SET_MODULE(module_name => lv_module_name 
             , action_name => lv_action_name); 

     -- Clear the client info, preventing any inter process confusion for anyone looking at it 
     DBMS_APPLICATION_INFO.SET_CLIENT_INFO(client_info => NULL); 
    END finalisation; 
END; 
/
+0

+1 Ví dụ tuyệt vời –

1

Sử dụng DBMS_PIPE để viết một thông điệp tới một ống tên. Trong một phiên khác, bạn có thể đọc các tin nhắn từ đường ống. Rất đơn giản, hoạt động như một sự quyến rũ!

procedure sendmessage(p_pipename varchar2 
         ,p_message varchar2) is 
     s number(15); 
    begin 
     begin 
     sys.dbms_pipe.pack_message(p_message); 
     exception 
     when others then 
      sys.dbms_pipe.reset_buffer; 
     end; 

     s := sys.dbms_pipe.send_message(p_pipename, 0); 

     if s = 1 
     then 
     sys.dbms_pipe.purge(p_pipename); 
     end if; 
    end; 




function receivemessage(p_pipename varchar2 
          ,p_timeout integer) return varchar2 is 
     n number(15); 
     chr varchar2(200); 
    begin 
     n := sys.dbms_pipe.receive_message(p_pipename, p_timeout); 

     if n = 1 
     then 
     return null; 
     end if; 

     sys.dbms_pipe.unpack_message(chr); 
     return(chr); 
    end; 
1

Nếu công việc của bạn kéo dài được xử lý một số lượng lớn các nhiệm vụ khá đồng đều có kích thước, bạn có thể tìm thấy phiên longops một cách tốt để theo dõi tiến độ công việc, cũng như cho phép bạn để ước lượng công việc sẽ bao lâu để hoàn thành.

DBMS_APPLICATION_INFO.set_session_longops

0

Nếu bạn có quyền truy cập vào shell từ môi trường PL/SQL bạn có thể gọi netcat:

BEGIN RUN_SHELL ('echo " '|| v_msg ||'" | nc' || v_host | | '' || v_port || '-w 5'); KẾT THÚC;

/

v_host là một máy chủ chạy script python mà đọc dữ liệu từ ổ cắm trên cổng v_port.

Tôi đã sử dụng thiết kế này khi tôi viết aplogr để theo dõi nhật ký vỏ và pl/sql.

Các vấn đề liên quan