注册
统计单条sql逻辑读、物理读以及cpu
技术分享/ 文章详情 /

统计单条sql逻辑读、物理读以及cpu

wuran 2026/06/18 368 0 0

一、说明

物理读操作会占用磁盘 I/O 资源,但dmsql日志、系统表以及系统视图中都未统计这类底层硬件层面的消耗,只记录物理读次数,所以只能根据物理读次数估算物理读数据量。
物理读的数据量(字节)=PHY_READ_CNT X PAGE_SIZE
例如物理读次数为1000,PAGE_SIZE=8192,则物理读数据量约为 1000 x 8KB=8MB。
当前已知的逻辑读和物理读统计路径
1、VSQL_STAT_HISTORY记录历史SQL语句(不含存储过程中的SQL)执行的资源开销,包含逻辑读、物理读、最大内存使用等。默认记录10000行。 2、VSQL_HISTORY记录最近执行的10000条SQL语句,包含执行时间、逻辑读、物理读等关键信息。不含存储过程中的SQL,当记录数达到上限后会按照先进先出的原则淘汰旧数据。
3、V$SYSSTAT 记录数据库运行时的逻辑读次数、物理写次数整体累加值,不记录具体SQL物理读信息。
4、SVR_LOG_PLN_STR=1时dmsql日志中记录执行计划信息,但估算行数不准确,参考价值不大。
5、SVR_LOG_PLN_STR=4时dmsql日志中记录trace信息,包括MEM_USED(排序、哈希表构造等中间计算占用内存)和DISK_USED(排序、哈希连接等操作临时表空间刷盘),可使用达梦日志分析工具对SQL日志进行入库分析,正则过滤关键字模糊统计出sql刷盘情况,但每次都需要单独统计,极为耗时。
1和2未记录所有sql物理读信息。3未记录具体SQL物理读信息。4无有效信息,5统计麻烦并且估算不准。
后续sqllog中不止会打印sql执行耗时、影响行数等信息,还会打印出sql逻辑读和物理读信息。当前只能通过采样方式粗略统计。

二、统计方式

1s抓取1次v$sql_stat信息到临时表,根据sql_text_id,sessid分组统计单条sql物理读、逻辑读以及cpu占用时间。

1、配置监控v$sql_stat

create table mon_sql_stat as select *,cast(sysdate as timestamp) from v$sql_stat;
truncate table mon_sql_stat;
--管理工具作业是1分钟起步,可以用DBMS_JOB配置精确到s
SP_INIT_JOB_SYS(0);
SP_INIT_JOB_SYS(1);
--创建一个自定义过程
CREATE OR REPLACE PROCEDURE PRO_MON_STAT AS
BEGIN
insert into mon_sql_stat select *,cast(sysdate as timestamp) from v$sql_stat;
commit;
END;
/
--创建JOB  
BEGIN
DBMS_JOB.ISUBMIT(1,'PRO_MON_STAT',SYSDATE,'SYSDATE+1/1440/60'); //每天1440分钟,即一分钟运行TEST过程一次,再除以60是秒
	COMMIT;
END;
/
--控制时间触发器的检查频率,单位秒 
alter   system set 'TIMER_TRIG_CHECK_INTERVAL'=1  ;
--查看JOB运行结果
SELECT * from mon_sql_stat;
--查DBMS_JOB.ISUBMIT创建了哪些job
SELECT * FROM SYSJOB.SYSJOBS WHERE SYS_FLAG = 2;
--一轮跑批结束,可根据作业id删除旧作业  
CALL DBMS_JOB.REMOVE(1);

2、统计逻辑读大小

逻辑读(logical reads)指的是SQL执行过程中从内存(Buffer Pool)中读取数据页的次数,它直接反映了SQL对内存访问的强度。尽管逻辑读通常比物理读(磁盘 I/O)快,但过高的逻辑读同样会带来严重的性能问题,优化逻辑读多的SQL,本质上是提升内存访问效率。它能带来多重收益:降低CPU消耗、缩短查询响应时间、提升系统并发能力、减少硬件资源需求。

--单位M
SELECT SUM(LOGIC_READ_CNT)*SF_GET_PAGE_SIZE()/1024.0/1024.0 AS sum_logic,COUNT(*) as cnt,SQL_TEXT_ID,SQL_TXT from (
select max(LOGIC_READ_CNT) as LOGIC_READ_CNT,SQL_TEXT_ID,sessid,SQL_TXT 
from mon_sql_stat
group by SQL_TEXT_ID,sessid,SQL_TXT ) temp
group by SQL_TEXT_ID,SQL_TXT
order by sum_logic desc;	

3、统计物理读大小

物理读(physical reads)是指数据库从磁盘读取数据页的次数。当SQL语句的物理读很高时,通常意味着需要大量访问磁盘I/O,而磁盘I/O是数据库系统中最常见的性能瓶颈之一。优化物理读多的SQL可直接缩短查询响应时间、释放 I/O 资源、降低系统负载、提升整体并发处理能力。

--单位M
SELECT SUM(PHY_READ_CNT)*SF_GET_PAGE_SIZE()/1024.0/1024.0 AS sum_phy,COUNT(*) as cnt,SQL_TEXT_ID,SQL_TXT from (
select max(PHY_READ_CNT) as PHY_READ_CNT,SQL_TEXT_ID,sessid,SQL_TXT 
from mon_sql_stat
group by SQL_TEXT_ID,sessid,SQL_TXT ) temp
group by SQL_TEXT_ID,SQL_TXT
order by sum_phy desc;	

4、统计占用cpu时间长的sql

当某些SQL执行时需要大量CPU时间(例如复杂的计算、大量数据排序、低效的索引扫描导致的重复计算等),会导致CPU使用率飙升,系统整体吞吐量下降,CPU时间被浪费在低效的计算上,无法服务于更多请求。

--占用cpu多的sql 单位ms			
SELECT SUM(MAX_cpu) AS sum_cpu,COUNT(*) as cnt,SQL_TEXT_ID,SQL_TXT from (			
select max(exec_cpu) as MAX_cpu,SQL_TEXT_ID,sessid,SQL_TXT 			
from mon_sql_stat			
group by SQL_TEXT_ID,sessid,SQL_TXT ) temp			
group by SQL_TEXT_ID,SQL_TXT			
order by sum_cpu desc;	

5、统计两次跑批物理读差距

表MON_SQL_STAT中存储第一次跑批监控信息,表mon_sql_stat_del_index存储第二次跑批监控信息。负的是第二次物理读变大,正的是第二次物理读降低。

WITH STAT1 AS (
SELECT SUM(PHY_READ_CNT)*SF_GET_PAGE_SIZE()/1024.0/1024.0 AS sum_phy,
       SUM(LOGIC_READ_CNT)*SF_GET_PAGE_SIZE()/1024.0/1024.0 AS sum_logic,
       COUNT(*) as cnt,SQL_TEXT_ID,SQL_TXT from (
select max(PHY_READ_CNT) as PHY_READ_CNT,max(LOGIC_READ_CNT) as LOGIC_READ_CNT,SQL_TEXT_ID,sessid,SQL_TXT 
from SYSDBA.MON_SQL_STAT
group by SQL_TEXT_ID,sessid,SQL_TXT ) temp
group by SQL_TEXT_ID,SQL_TXT
),STAT2 AS (
SELECT SUM(PHY_READ_CNT)*SF_GET_PAGE_SIZE()/1024.0/1024.0 AS sum_phy,
       SUM(LOGIC_READ_CNT)*SF_GET_PAGE_SIZE()/1024.0/1024.0 AS sum_logic,
       COUNT(*) as cnt,SQL_TEXT_ID,SQL_TXT from (
select max(PHY_READ_CNT) as PHY_READ_CNT,max(LOGIC_READ_CNT) as LOGIC_READ_CNT,SQL_TEXT_ID,sessid,SQL_TXT 
from mon_sql_stat_del_index
group by SQL_TEXT_ID,sessid,SQL_TXT ) temp
group by SQL_TEXT_ID,SQL_TXT
)	
SELECT STAT1.sum_phy AS PHY1,
       STAT2.sum_phy AS PHY2, 
       STAT1.sum_phy - STAT2.sum_phy AS PHY_DIFF,
       STAT1.sum_logic AS LOGIC1,
       STAT2.sum_logic AS LOGIC2, 
       STAT1.sum_logic - STAT2.sum_logic AS LOGIC_DIFF,
       STAT1.sum_phy + STAT1.sum_logic AS TOTAL1,
       STAT2.sum_phy + STAT2.sum_logic AS TOTAL2,
       STAT1.sum_phy + STAT1.sum_logic - STAT2.sum_phy - STAT2.sum_logic AS TOTAL_DIFF,
       STAT1.cnt - STAT2.cnt AS CNT_DIFF,
       STAT1.SQL_TEXT_ID,
       STAT1.SQL_TXT
FROM STAT1
LEFT JOIN STAT2
ON STAT1.SQL_TEXT_ID = STAT2.SQL_TEXT_ID
ORDER BY TOTAL_DIFF DESC;
评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服