我的 TEMP 表空间监控正确吗?

问题描述 投票:0回答:1

我在 ORACLE 中通过 DBLINKS 开发了这个 TEMP 表空间监视器,如果任何临时表空间达到 v_used 调用的任何百分比,它会发送电子邮件:

CREATE OR REPLACE PROCEDURE SP_TEMP_MON(
    v_used NUMBER
) AS
    v_sql                        VARCHAR2(4000);
    v_html                       CLOB := EMPTY_CLOB();
    v_execution_date             DATE := SYSDATE;
    v_db_link_name               VARCHAR2(128);
    v_link_open                  BOOLEAN := FALSE;
    v_actions_found              BOOLEAN := FALSE;
    v_total_mb                   NUMBER;
    v_query_mb_used              NUMBER;
    v_tablespace_mb_used         NUMBER;
    v_query_percentage_used      NUMBER;
    v_tablespace_percentage_used NUMBER;

    TYPE temp_details_type IS RECORD (
        tablespace         VARCHAR2(128),
        os_username        VARCHAR2(128),
        sql_text           VARCHAR2(4000),
        query_mb_used      NUMBER,
        tablespace_mb_used NUMBER,
        total_mb           NUMBER
    );
    TYPE temp_details_table IS TABLE OF temp_details_type;

    temp_details_list temp_details_table := temp_details_table();

    CURSOR c_dblinks IS
        SELECT NOMBREDBLINK || '.DBLINK.DOMAIN.COM' AS NOMBREDBLINK
        FROM BDHIST.CATALOGO_DBLINKS
        WHERE CONECTA = 'SI' AND NODO IS NULL;

BEGIN
    -- We iterate through all the user DBLINKs defined in the database to audit.
    FOR rec_link IN c_dblinks LOOP
        v_db_link_name := rec_link.NOMBREDBLINK;
        v_link_open := FALSE;

        BEGIN
            -- Building the dynamic query to obtain tablespace usage information
            v_sql := 'WITH sort_usage AS (
                            SELECT 
                                T.tablespace,
                                SUM(T.blocks * TBS.block_size) / 1024 / 1024 AS mb_used,
                                S.osuser,
                                Q.sql_text
                            FROM 
                                v$sort_usage@'||v_db_link_name||' T
                            JOIN 
                                v$session@'||v_db_link_name||' S ON T.session_addr = S.saddr
                            LEFT JOIN 
                                v$sqlarea@'||v_db_link_name||' Q ON T.sqladdr = Q.address
                            JOIN 
                                dba_tablespaces@'||v_db_link_name||' TBS ON T.tablespace = TBS.tablespace_name
                            GROUP BY 
                                T.tablespace, S.osuser, Q.sql_text
                        ),
                        tablespace_summary AS (
                            SELECT   
                                A.tablespace_name AS tablespace,
                                SUM(A.used_blocks * D.block_size) / 1024 / 1024 AS mb_used,
                                SUM(D.mb_total) AS total_mb
                            FROM
                                v$sort_segment@'||v_db_link_name||' A
                            JOIN
                                (SELECT
                                    B.name,
                                    C.block_size,
                                    SUM(C.bytes) / 1024 / 1024 AS mb_total
                                FROM
                                    v$tablespace@'||v_db_link_name||' B
                                JOIN
                                    v$tempfile@'||v_db_link_name||' C ON B.ts# = C.ts#
                                GROUP BY 
                                    B.name,
                                    C.block_size) D ON A.tablespace_name = D.name
                            GROUP BY 
                                A.tablespace_name
                        )
                        SELECT 
                            ts.tablespace,
                            su.osuser,
                            su.sql_text,
                            su.mb_used AS query_mb_used,
                            ts.mb_used AS tablespace_mb_used,
                            ts.total_mb
                        FROM 
                            tablespace_summary ts
                        JOIN 
                            sort_usage su ON ts.tablespace = su.tablespace
                        ORDER BY 
                            query_mb_used DESC';

            EXECUTE IMMEDIATE v_sql BULK COLLECT INTO temp_details_list;
            v_link_open := TRUE;

           -- Print headers if data found
            IF temp_details_list.COUNT > 0 THEN
                -- Check the usage percentage and whether it meets the mail sending condition
                v_actions_found := FALSE;
                       
                FOR i IN 1..temp_details_list.COUNT LOOP
                    v_total_mb := temp_details_list(i).total_mb;
                    v_tablespace_mb_used := temp_details_list(i).tablespace_mb_used;
                    v_tablespace_percentage_used := (v_tablespace_mb_used / v_total_mb) * 100;

                    IF v_tablespace_percentage_used >= v_used OR (v_total_mb - v_tablespace_mb_used) / v_total_mb * 100 <= 100 - v_used THEN
                        v_actions_found := TRUE;
                        EXIT;
                    END IF;
                END LOOP;

                -- HTML headers
                v_html :=
                    v_html
                    || '<h2>DBLINK: ' || v_db_link_name || '</h2>'
                    || '<table border="1" cellpadding="5" cellspacing="0">'
                    || '<tr>'
                    || '<th>TABLESPACE</th>'
                    || '<th>OS_USERNAME</th>'
                    || '<th>SQL_TEXT</th>'
                    || '<th>QUERY_MB_USED</th>'
                    || '<th>TOTAL_MB</th>'
                    || '<th>QUERY_PERCENTAGE_USED</th>'
                    || '<th>TABLESPACE_PERCENTAGE_USED</th>'
                    || '</tr>';

                FOR i IN 1..temp_details_list.COUNT LOOP
                    v_query_mb_used := temp_details_list(i).query_mb_used;
                    v_query_percentage_used := (v_query_mb_used / v_total_mb) * 100;
                    v_html :=
                        v_html
                        || '<tr>'
                        || '<td>' || temp_details_list(i).tablespace || '</td>'
                        || '<td>' || temp_details_list(i).os_username || '</td>'                            
                        || '<td>' || temp_details_list(i).sql_text || '</td>'
                        || '<td>' || TO_CHAR(temp_details_list(i).query_mb_used) || '</td>'
                        || '<td>' || TO_CHAR(temp_details_list(i).total_mb) || '</td>'
                        || '<td>' || TO_CHAR(v_query_percentage_used, 'FM9999990.000') || '%</td>'
                        || '<td>' || TO_CHAR(v_tablespace_percentage_used, 'FM9999990.000') || '%</td>'
                        || '</tr>';
                END LOOP;

                v_html := v_html || '</table>';
            ELSE
                v_html :=
                    v_html
                    || '<h2>Detalles de DBLINK: ' || v_db_link_name || '</h2>'
                    || '<p>TEMP not in use.</p>';
            END IF;

            COMMIT;

            IF v_link_open THEN
                EXECUTE IMMEDIATE 'BEGIN DBMS_SESSION.CLOSE_DATABASE_LINK('''||v_db_link_name||'''); END;';
                v_link_open := FALSE;
            END IF;

        EXCEPTION
            WHEN OTHERS THEN
                IF v_link_open THEN
                    EXECUTE IMMEDIATE 'BEGIN DBMS_SESSION.CLOSE_DATABASE_LINK('''||v_db_link_name||'''); END;';
                END IF;

                DBMS_OUTPUT.PUT_LINE('Error processing DBLINK ' || v_db_link_name || ': ' || SQLERRM);
        END;
    END LOOP;

   IF v_actions_found THEN
        MONITORING_SCHEMA.PG_ENVIO_MAIL.entrega(
            vg_from      => '[email protected]',
            vg_to        => '[email protected]',
            vg_asunto    => 'TEMP Monitoring',
            vg_cuerpo    => v_html,
            vg_firma     => 'sender',
            vg_cc        => '[email protected]'
        );
    END IF;

EXCEPTION
    WHEN OTHERS
    THEN
        DBMS_OUTPUT.put_line(DBMS_UTILITY.format_error_stack);
END;
/
SHOW ERRORS;

我设置了一个作业,当 v_used = 85% 的存储空间已满(任何 DBLINK)时,每 5 分钟执行一次发送邮件的过程,但我被告知,当它已满时,它不会发送电子邮件,或者至少会发送电子邮件需要时不捕获完整的表空间。我的问题是,主要查询正确吗?

WITH sort_usage AS (
                            SELECT 
                                T.tablespace,
                                SUM(T.blocks * TBS.block_size) / 1024 / 1024 AS mb_used,
                                S.osuser,
                                Q.sql_text
                            FROM 
                                v$sort_usage@'||v_db_link_name||' T
                            JOIN 
                                v$session@'||v_db_link_name||' S ON T.session_addr = S.saddr
                            LEFT JOIN 
                                v$sqlarea@'||v_db_link_name||' Q ON T.sqladdr = Q.address
                            JOIN 
                                dba_tablespaces@'||v_db_link_name||' TBS ON T.tablespace = TBS.tablespace_name
                            GROUP BY 
                                T.tablespace, S.osuser, Q.sql_text
                        ),
                        tablespace_summary AS (
                            SELECT   
                                A.tablespace_name AS tablespace,
                                SUM(A.used_blocks * D.block_size) / 1024 / 1024 AS mb_used,
                                SUM(D.mb_total) AS total_mb
                            FROM
                                v$sort_segment@'||v_db_link_name||' A
                            JOIN
                                (SELECT
                                    B.name,
                                    C.block_size,
                                    SUM(C.bytes) / 1024 / 1024 AS mb_total
                                FROM
                                    v$tablespace@'||v_db_link_name||' B
                                JOIN
                                    v$tempfile@'||v_db_link_name||' C ON B.ts# = C.ts#
                                GROUP BY 
                                    B.name,
                                    C.block_size) D ON A.tablespace_name = D.name
                            GROUP BY 
                                A.tablespace_name
                        )
                        SELECT 
                            ts.tablespace,
                            su.osuser,
                            su.sql_text,
                            su.mb_used AS query_mb_used,
                            ts.mb_used AS tablespace_mb_used,
                            ts.total_mb
                        FROM 
                            tablespace_summary ts
                        JOIN 
                            sort_usage su ON ts.tablespace = su.tablespace
                        ORDER BY 
                            query_mb_used DESC'

或者我的方法遗漏了一些东西?

oracle plsql database-administration tablespace
1个回答
0
投票

如果您有 RAC 数据库(多个主机安装数据库),则需要使用

gv$sort_segment
(或者,
gv$sort_usage
)而不是单节点
v$
版本,该版本不会捕获正在消耗的数据通过您当前未连接的其他实例中的会话。这会低估所使用的数量。

其次,一旦纠正了这个问题,您还需要更改此行以使用

MAX
而不是
SUM

          SUM(D.mb_total) AS total_mb

由于这是在排序段的级别,并且每个实例在每个临时空间中都可以有一个段,因此外部查询的粒度比内部查询的粒度低,因此

SUM
会乘以已经正确的表空间大小比应有的大得多。将
SUM
更改为
MAX
即可修复该问题。

一个潜在的问题是

gv$sort_usage
只会显示正在进行的SQL工作区——如果没有,你什么也得不到。这将消除您查询中的任何结果,因为您是在最后加入的。请记住,SQL 排序/哈希区域并不是唯一可以使用 temp 的区域。例如,全局临时表也可以,但它们不会显示在该视图中。

您还可以使用

gv$temp_extent_pool

为了有效,你确实需要每分钟执行一次。 5分钟间隔太远了——5分钟内就会消耗掉很多温度。如果它在本地运行而不是通过数据库链接运行也是最好的。

© www.soinside.com 2019 - 2024. All rights reserved.