Oracle数据库执行慢问题排查详细过程

 更新时间:2023年07月25日 15:51:38   作者:kida_yuan  
这篇文章主要给大家介绍了关于Oracle数据库执行慢问题排查的详细过程,在企业级应用中,数据库的稳定性和性能是至关重要的,文中给出了详细的代码实例,需要的朋友可以参考下

文中使用的Oracle版本为10g。

这是之前在工作中遇到的慢查询排查记录,为了防杠先做个声明。

“All Roads Lead to Rome”

以下方法是本人处理思路以及在排除掉其他外部因素后,只针对数据库层面的排查内容。当然了肯定有更好的排查方式,这里只是提供一个方案而已。

1. 若出现插入速度慢或者无法插入数据的情况下,先检查表空间

SELECT UPPER(F.TABLESPACE_NAME) "表空间名",
D.TOT_GROOTTE_MB "表空间大小(M)",
D.TOT_GROOTTE_MB - F.TOTAL_BYTES "已使用空间(M)",
TO_CHAR(ROUND((D.TOT_GROOTTE_MB - F.TOTAL_BYTES) / D.TOT_GROOTTE_MB * 100, 2), '990.99') || '%' "使用比",
F.TOTAL_BYTES "空闲空间(M)",
F.MAX_BYTES "最大块(M)"
FROM (SELECT TABLESPACE_NAME,
        ROUND(SUM(BYTES) / (1024 * 1024), 2) TOTAL_BYTES,
        ROUND(MAX(BYTES) / (1024 * 1024), 2) MAX_BYTES   
        FROM SYS.DBA_FREE_SPACE   
        GROUP BY TABLESPACE_NAME) F,
(SELECT DD.TABLESPACE_NAME,
           ROUND(SUM(DD.BYTES) / (1024 * 1024), 2) TOT_GROOTTE_MB   
           FROM SYS.DBA_DATA_FILES DD   
           GROUP BY DD.TABLESPACE_NAME) D
WHERE D.TABLESPACE_NAME = F.TABLESPACE_NAME
--and F.TABLESPACE_NAME = '<tablespace>'
ORDER BY 1;

上面的脚本已经将列名都用中文标识清楚了,若用户表空间使用率达到峰值,则基本只能查询,其他的操作都不能做了。除此之外,本脚本还可以看到系统的表空间情况,其中值得注意的是UNDOTBS1这个表空间,如下图:

请添加图片描述

这个是回滚表空间,越大越能够储存回滚段。在做提交操作或者复杂运算的时候这里的使用率会飞涨。这个表空间是系统自动回收的,当系统判断资源不需要被使用之后表空间将会被回收。但若这个表空间长时间不回收就需要留意是否存在大批量的提交操作甚至锁表情况出现。

2. 表空间正常但发现只能查询不能修改或者插入时,可以初步判定存在锁表的可能性

通过以下语句查询是否存在表级锁

SELECT SESS.SID,
       SESS.SERIAL#,
       LO.ORACLE_USERNAME,
       LO.OS_USER_NAME,
       AO.OBJECT_NAME,
       LO.LOCKED_MODE
  FROM V$LOCKED_OBJECT LO, DBA_OBJECTS AO, V$SESSION SESS
 WHERE AO.OBJECT_ID = LO.OBJECT_ID
   AND LO.SESSION_ID = SESS.SID;

一般情况下会在做DML操作时系统会自动分配一个行级排它锁。同时这个事务就会获得一个表锁以防止其他的DDL操作影响DML操作。以上说的都是系统自动操作的,但是需要用到上面语句来进行查询的时候应该大多数情况都是产生了死锁,即多个DML操作产生了冲突引起的锁。这个时候就只能查询出来锁的SID和SERIAL#来将其KILL掉。除此之外还有其他找锁表的语句,譬如:

SELECT (SELECT USERNAME FROM V$SESSION WHERE SID = A.SID) BLOCKER,
       A.SID,
       'IS BLOCKING',
       (SELECT USERNAME FROM V$SESSION WHERE SID = B.SID) BLOCKEE,
       B.SID
  FROM V$LOCK A, V$LOCK B
 WHERE A.BLOCK = 1
   AND B.REQUEST > 0
   AND A.ID1 = B.ID1
   AND A.ID2 = B.ID2;

找到SID和SERIAL#字段信息并KILL掉当前死锁执行脚本如下:

ALTER SYSTEM KILL SESSION 'SID,SERIAL#';

还有很多情况也会产生出锁表的现象,不过本人经历过最多的锁表原因都在于:

  • 应用程序的编写不当引起,包括JDBC连接没有正常关闭,通过循环提交负责级联更新操作等
  • 数据库 存储过程/触发器 编写逻辑混乱引起的同表资源抢占(一个操作没有完成就又要提交另一个操作)
  • 数据库利用定时器模仿多线程进行同表数据DML操作

3. 服务器端出现多个Oracle进程并CPU占用率高

要想知道是那个数据库用户在占用CPU可以使用以下语句找到:

SELECT A.SID,
       SPID,
       STATUS,
       SUBSTR(A.PROGRAM, 1, 40) PROG,
       A.TERMINAL,
       OSUSER,
       VALUE / 60 / 100 VALUE
  FROM V$SESSION A, V$PROCESS B, V$SESSTAT C
 WHERE C.STATISTIC# = 12
   AND C.SID = A.SID
   AND A.PADDR = B.ADDR 
   -- AND STATUS = 'ACTIVE'  
 ORDER BY VALUE DESC;

执行后如下图所示,可以通过图中的字段知道哪个用户是通过哪种方式连接到数据库的,是否在线状态,数据库中执行id是什么,操作系统中是那个用户,CPU耗时多长时间,以此来定为那个用户。

请添加图片描述

4. 进一步深挖究竟执行什么导致CPU使用率高

SELECT OSUSER, USERNAME, SQL_TEXT, ADDRESS, HASH_VALUE
FROM V$SESSION A, V$SQLTEXT B
WHERE A.SQL_ADDRESS = B.ADDRESS
--AND USERNAME = 'I_INFO' 
ORDER BY ADDRESS, PIECE;

执行之后如下图所示,查询出来后可以根据USERNAME来进行筛选,再来拿到语句的ADDRESS(SGA内存地址)和HASH_VALUE(Oracle Hash值)进行后续查询。

请添加图片描述

下面脚本将根据ADDRESS和HASH_VALUE来找到对应SQL执行性能消耗情况:

SELECT HASH_VALUE,
       BUFFER_GETS,
       DISK_READS,
       EXECUTIONS,
       PARSE_CALLS,
       CPU_TIME
  FROM V$SQLAREA
 WHERE HASH_VALUE = 1977390476
   AND ADDRESS = HEXTORAW('000000018B83E578');

执行之后可以看到BUFFER_GETS(所有子游标运行这条语句导致的读内存次数),DISK_READS(所有子游标运行这条语句导致的读磁盘次数),EXECUTIONS(所有子游标的执行这条语句次数),PARSE_CALLS (语句的解析调用(软、硬)次数),CPU_TIME (语句被解析和执行的CPU时间),如下图:

请添加图片描述

一般来说EXECUTIONS,BUFFER_GETS越高表示读内存多,磁盘少是比较理想的状态,因此越高越好。之后若发现语句资源消耗异常可以从SQL_TEXT找到对应的语句,放到执行计划里面进行分析看看具体是那个地方造成性能问题。

5. 还有另一种解法获取等待时间长的用户和执行语句

SELECT S.SID, S.USERNAME, SUM(A.WAIT_TIME + A.TIME_WAITED) TOTAL_WAIT_TIME
  FROM V$ACTIVE_SESSION_HISTORY A, V$SESSION S
 WHERE A.SAMPLE_TIME BETWEEN SYSDATE - 30 / 2880 AND SYSDATE
 GROUP BY S.SID, S.USERNAME
 ORDER BY TOTAL_WAIT_TIME DESC;
SELECT A.PROGRAM,
       A.SESSION_ID,
       A.USER_ID,
       D.USERNAME,
       S.SQL_TEXT,
       SUM(A.WAIT_TIME + A.TIME_WAITED) TOTAL_WAIT_TIME
  FROM V$ACTIVE_SESSION_HISTORY A, V$SQLAREA S, DBA_USERS D
 WHERE A.SAMPLE_TIME BETWEEN SYSDATE - 30 / 2880 AND SYSDATE
   AND A.SQL_ID = S.SQL_ID
   AND A.USER_ID = D.USER_ID
 GROUP BY A.PROGRAM, A.SESSION_ID, A.USER_ID, S.SQL_TEXT, D.USERNAME;

两个脚本里面都有TOTAL_WAIT_TIME字段,这个字段就是这些用户和SQL从产生开始到目前为止等待的最长时间,可以根据这个定位用户和SQL。若问题仍然存在,就需要注意内存使用情况和Oracle的SGA和PGA分配情况(这个网上有太多方法了就不再叙述)。

后日谈

在另一次慢查询分析时在执行到了第四步“进一步深挖究竟执行什么导致CPU使用率高”后找到了执行慢的语句,进一步执行分析计划后看到语句本应该是主键的ID字段没有走到索引,本以为Oracle会自动基于成本规则选择了别的执行方式。但并没有…后来将这个结果与所在项目组沟通才知道他们在做数据迁移时执行脚本用CTAS方式建表忘记额外生成主键了。其实我想说的是,只要不是过于复杂的业务过程或者大规模运算的情况下哪有那么多性能问题,往往性能问题都是因为一些“粗心大意”下引起的,听我说多用checklist准没错的。

到此这篇关于Oracle数据库执行慢问题排查详细过程的文章就介绍到这了,更多相关Oracle执行慢问题排查内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Oracle去除重复数据

    Oracle去除重复数据

    这篇文章介绍了Oracle去除重复数据的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • Linux系统下Oracle数据库监听启动关闭命令详解

    Linux系统下Oracle数据库监听启动关闭命令详解

    现在很多朋友在学习linux下oracle 数据库的时候可能都发现了一个问题,oracle数据库的服务不能自动启动,这篇文章主要给大家介绍了关于Linux系统下Oracle数据库监听启动关闭命令的相关资料,需要的朋友可以参考下
    2024-01-01
  • Oracle如何通过执行计划查看查询语句是否使用索引

    Oracle如何通过执行计划查看查询语句是否使用索引

    这篇文章主要介绍了Oracle如何通过执行计划查看查询语句是否使用索引问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Oracle并行操作之并行查询实例解析

    Oracle并行操作之并行查询实例解析

    这篇文章主要介绍了Oracle并行操作的并行查询技术,需要的朋友可以参考下
    2014-07-07
  • Oracle触发器实例代码

    Oracle触发器实例代码

    Oracle触发器,用于选单后修改选单的表的触发动作。接下来通过本文给大家分享Oracle触发器实例代码,需要的的朋友参考下吧
    2017-04-04
  • Oracle审计日志快速设置

    Oracle审计日志快速设置

    Oracle数据库中的审计功能用于监控和记录数据库活动,有助于增加数据库的安全性,默认情况下,Oracle 11g会开启数据库审计功能,并将审计日志保存在SYSTEM表空间中,可能导致该表空间迅速膨胀,为了控制空间使用,可以更改审计日志的存储位置
    2024-10-10
  • Oracle如何使用PL/SQL调试存储过程

    Oracle如何使用PL/SQL调试存储过程

    这篇文章主要介绍了Oracle如何使用PL/SQL调试存储过程,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • Oracle数据库如何更改数据文件位置

    Oracle数据库如何更改数据文件位置

    这篇文章主要给大家介绍了关于Oracle数据库如何更改数据文件位置的相关资料,Oracle数据库的数据文件的位置和信息都被记录在控制文件中,需要的朋友可以参考下
    2023-08-08
  • 修改oracle密码有效期限制的两种思路详解

    修改oracle密码有效期限制的两种思路详解

    这篇文章给大家带来了修改oracle密码有效期限制的两种思路,非常不错,具有一定的参考借鉴价值,需要的朋友参考下吧
    2018-09-09
  • oracle数据库的基本使用教程(建表,操作表等)

    oracle数据库的基本使用教程(建表,操作表等)

    这篇文章主要给大家介绍了关于oracle数据库的基本使用(建表,操作表等)的相关资料,包含了Oracle创建表(create table as)使用方法、操作技巧、实例演示和注意事项,需要的朋友可以参考下
    2024-01-01

最新评论