数据字典死锁

Posted Leo_wlCnBlogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据字典死锁相关的知识,希望对你有一定的参考价值。

数据字典是 Oracle 中存放数据库信息的地方,用于描述数据。比如一个表的创建者信息、创建时间信息、所属表空间信息、用户访问权限信息等。数据字典由表和视图构成,数据字典中的表是不允许被直接访问的,但可以访问数据字典中的视图(前提是要有足够的权限)。

数据字典中的表和视图属于 SYS 用户,被存放到 SYSTEM 表空间中,数据字典中的视图都是只读的,可以被查询,但不能被修改。Oracle 中的数据字典有静态和动态之分:

  • 1、静态数据字典:在用户访问这类数据字典时,数据不会发生改变的。
  • 2、动态数据字典:依赖数据库运行的性能,反映数据库运行的一些内在信息,所以在访问这类数据字典时往往是动态变化的。

1、静态数据字典

静态数据字典中的视图可根据视图名称的前缀分为三类,分别是:

  • 1、USER_*视图:此类视图提供了当前用户所拥有的对象信息,即当前用户模式下所有对象的相关信息。
  • 2、ALL_*视图:此类视图提供了当前用户能够访问的对象信息,即当前用户能够访问到的所有对象的相关信息。
  • 3、DBA_*视图:此类视图提供了数据库中所有的对象信息。前提是当前用户具有访问这些数据库对象的权限,否则查不到数据。

1.1、实用静态数据字典

表空间

SELECT * FROM DBA_TABLESPACES;  -- 数据库中所有的表空间信息(USER_TABLESPACES)
SELECT * FROM DBA_TS_QUOTAS;  -- 数据库中所有的表空间配额信息(USER_TS_QUOTAS)
SELECT * FROM DBA_DATA_FILES; -- 表空间和数据文件对应关系
SELECT * FROM DBA_TEMP_FILES; -- 临时表空间和数据文件对应关系
SELECT * FROM DBA_SEGMENTS; -- 分配给数据库中所有段的存储信息(USER_SEGMENTS)
SELECT * FROM DBA_EXTENTS; -- 数据库中所有表空间中包含段的区域信息(USER_EXTENTS)

角色、权限

SELECT * FROM DBA_ROLES; -- 当前数据库中的所有角色信息
SELECT * FROM SESSION_ROLES; -- 当前用户被授予的所有角色
SELECT * FROM SESSION_PRIVS; -- 当前用户被授予的所有权限

SELECT * FROM ROLE_SYS_PRIVS t WHERE t.ROLE=\'CONNECT\'; -- 查询 CONNECT 角色拥有的系统权限
SELECT * FROM ROLE_TAB_PRIVS t WHERE t.ROLE=\'CONNECT\'; -- 查询 CONNECT 角色拥有的对象权限

用户、用户角色、用户权限

SELECT * FROM DBA_USERS;  -- 当前数据库的所有用户信息(USER_USERS、ALL_USERS)
SELECT * FROM DBA_ROLE_PRIVS;  -- 数据库中所有的角色权限信息(USER_ROLE_PRIVS)
SELECT * FROM DBA_SYS_PRIVS;  -- 数据库中所有的系统权限信息(USER_SYS_PRIVS)
SELECT * FROM DBA_TAB_PRIVS;  -- 数据库中所有的对象权限信息(USER_TAB_PRIVS、ALL_TAB_PRIVS)
SELECT * FROM DBA_COL_PRIVS;  -- 数据库中所有的对象列权限信息(USER_COL_PRIVS、ALL_COL_PRIVS)

SELECT * FROM USER_TAB_PRIVS_RECD; -- 查询当前用户拥有的对象权限
SELECT * FROM USER_TAB_PRIVS_MADE; -- 查询当前用户已授予出去的对象权限
SELECT * FROM USER_COL_PRIVS_RECD; -- 查询当前用户拥有的关于列的对象权限
SELECT * FROM USER_COL_PRIVS_MADE; -- 查询当前用户授予出去的列的对象权限

表、列:

SELECT * FROM DBA_TABLES;  -- 数据库中所有的表信息(USER_TABLES、ALL_TABLES)
SELECT * FROM DBA_TAB_COLUMNS;  -- 数据库中所有的列信息(USER_TAB_COLUMNS、ALL_TAB_COLUMNS)

注释:

SELECT * FROM DBA_TAB_COMMENTS;  -- 数据库中所有的表注释(USER_TAB_COMMENTS、ALL_TAB_COMMENTS)
SELECT * FROM DBA_COL_COMMENTS;  -- 数据库中所有的列注释(USER_COL_COMMENTS、ALL_COL_COMMENTS)

约束:

SELECT * FROM DBA_CONSTRAINTS;  -- 数据库中所有的约束信息(USER_CONSTRAINTS、ALL_CONSTRAINTS)
SELECT * FROM DBA_CONS_COLUMNS;  -- 数据库中所有的约束与列信息(USER_CONS_COLUMNS、ALL_CONS_COLUMNS)

索引:

SELECT * FROM DBA_INDEXES;  -- 数据库中所有的索引信息(USER_INDEXES、ALL_INDEXES)
SELECT * FROM DBA_IND_COLUMNS;  -- 数据库中所有的索引与列信息(USER_IND_COLUMNS、ALL_IND_COLUMNS)

视图:

SELECT * FROM DBA_VIEWS;  -- 数据库中所有的视图信息(USER_VIEWS、ALL_VIEWS)

存储过程:

SELECT * FROM DBA_PROCEDURES;  -- 数据库中所有的视图信息(USER_PROCEDURES、ALL_PROCEDURES)

触发器:

SELECT * FROM DBA_TRIGGERS;  -- 数据库中所有的触发器信息(USER_TRIGGERS、ALL_TRIGGERS)

任务:

SELECT * FROM DBA_JOBS;  -- 数据库中所有的任务信息(USER_JOBS、ALL_JOBS)
SELECT * FROM DBA_SCHEDULER_JOBS; -- 数据库中所有调度程序作业的信息(USER_SCHEDULER_JOBS、ALL_SCHEDULER_JOBS)

序列:

SELECT * FROM DBA_SEQUENCES;  -- 数据库中所有的序列信息(USER_SEQUENCES、ALL_SEQUENCES)

同义词:

SELECT * FROM DBA_SYNONYMS;  -- 数据库中所有的同义词信息(USER_SYNONYMS、ALL_SYNONYMS)

所有模式对象:包括表、视图、函数、存储过程、触发器、包、索引、序列等,还可以通过object_type字段来查询指定类型的对象信息。

SELECT * FROM DBA_OBJECTS;  -- 数据库中所有的模式对象信息(USER_OBJECTS、ALL_OBJECTS)

1.2、运用静态数据字典

查询T_STAFF表上的索引信息

SELECT t.* FROM USER_INDEXES t WHERE t.table_name=\'T_STAFF\';
SELECT t.* FROM USER_IND_COLUMNS t WHERE t.table_name=\'T_STAFF\';

查询当前用户模式下的所有索引

SELECT t1.table_type,t1.table_name,t1.index_name,t1.uniqueness,t2.column_name
FROM USER_INDEXES t1,USER_IND_COLUMNS t2
WHERE t1.table_name=t2.table_name AND t1.index_name=t2.index_name
ORDER BY 1,2,3,4,5;

查询被禁用的触发器

SELECT t.owner,t.trigger_name,t.trigger_type,t.triggering_event,t.table_owner||\'.\'||t.table_name tname
FROM dba_triggers t WHERE t.owner=\'DEMO\' AND t.status<>\'ENABLED\' ORDER BY 1,2;

查询对象的定义语句

SELECT t.text FROM USER_SOURCE t WHERE t.name=\'FN_NOW\' ORDER BY t.line;

查询编译无效的对象

SELECT t.owner,t.object_name,t.object_type,t.last_ddl_time
FROM dba_objects t WHERE t.owner=\'DEMO\' AND t.status<>\'INVALID\' ORDER BY 1,2;

查询 DEMO 用户模式中的T_STAFF占用空间大小

SELECT t.owner,t.segment_type,t.segment_name,SUM(t.bytes)/1024/1024 "大小(M)"
FROM DBA_SEGMENTS t
WHERE t.owner=\'DEMO\' AND t.segment_name=\'T_STAFF\'
GROUP BY t.owner,t.segment_type,t.segment_name
ORDER BY 1,2,3;

统计表空间使用情况

WITH t1 AS(
  SELECT t.tablespace_name,SUM(t.bytes)/1024/1024 sum_bytes 
  FROM DBA_DATA_FILES t GROUP BY t.tablespace_name
), t2 AS(
  SELECT t.tablespace_name,SUM(t.bytes)/1024/1024 sum_bytes,MAX(t.bytes)/1024/1024 max_bytes 
  FROM DBA_FREE_SPACE t GROUP BY t.tablespace_name
)
SELECT t1.tablespace_name "表空间名称",ROUND(t1.sum_bytes,2) "表空间大小(m)",
  ROUND(t1.sum_bytes-t2.sum_bytes,2) "已使用空间(m)",ROUND(t2.sum_bytes,2) "空闲空间(m)",
  ROUND((t1.sum_bytes-t2.sum_bytes)/t1.sum_bytes*100,2) "已用比例(%)",
  ROUND(t2.max_bytes,2) "最大空闲块(m)"
FROM t1,t2 WHERE t1.tablespace_name=t2.tablespace_name ORDER BY 4 DESC;

2、动态数据字典

由于动态数据字典中的数据会在数据库打开和使用时不断更新,且其内容主要与性能相关,故又被称之为动态性能视图。动态性能视图提供有关内部磁盘结构和内存结构的数据,这些数据可以被查询但不能被修改。Oracle DBA 使用动态性能视图监视和调优数据库。

实际的动态性能视图都是由前缀V_$标识的,每个动态性能视图都有对应的同义词,这些同义词有一个统一的前缀V$。事实上前缀为V_$的视图是不允许用户访问的,只能访问前缀是V$的同义词。因为数据是动态的,所以不能保证动态性能视图上读取数据的一致性。

几乎每个V$视图,都已一个与之对应的GV$视图,即全局V$视图。查询GV$视图会从所有限定的示例中检索V$视图。除V$中的信息之外,每个GV$视图还包含一个名为INST_ID的数据类型为 NUMBER 的列。INST_ID列显示从中获取关联的V$视图信息的实例编号。INST_ID列可以用作过滤器,从可用实例的子集中检索V$信息。

2.1、实用动态性能视图

SELECT * FROM V$CONTROLFILE; -- 控制文件信息
SELECT * FROM V$TABLESPACE; -- 控制文件中的表空间信息
SELECT * FROM V$DATABASE; -- 控制文件中有关数据库的信息
SELECT * FROM V$DATAFILE; -- 控制文件中的数据文件信息
SELECT * FROM V$TEMPFILE; -- 临时文件信息
SELECT * FROM V$RESOURCE; -- 有关系统资源的资源名称和地址信息
SELECT * FROM V$RESOURCE_LIMIT; -- 有关系统资源的全局资源使用信息
SELECT * FROM V$INSTANCE; -- 当前实例的状态,包含 Oracle 的版本信息
SELECT * FROM V$SESSTAT; -- 活动会话的统计信息
SELECT * FROM V$SESSION; -- 每个当前会话的会话信息
SELECT * FROM V$SESSION_WAIT; -- 活动会话正在等待的资源或事件
SELECT * FROM V$SESSION_EVENT; -- 会话等待事件的信息
SELECT * FROM V$SYSTEM_EVENT; -- 某个事件的等待事件汇总信息
SELECT * FROM V$LOCK; -- 数据库当前持有的锁和未完成的锁定或闩锁请求
SELECT * FROM V$ACCESS; -- 当前对对象施加的锁的信息,这些锁是为了确保在执行 SQL 时不会从库缓存中过期
SELECT * FROM V$SQL; -- 共享 SQL 区域的统计信息,通常在查询执行结束时更新
SELECT * FROM V$SQLTEXT; -- SGA 中属于共享 SQL 游标的 SQL 语句文本
SELECT * FROM V$SQLAREA; -- 共享 SQL 区域的统计信息
SELECT * FROM V$SQLSTATS; -- SQL 游标的基本性能统计信息
SELECT * FROM V$CONTEXT; -- 当前会话中的参数信息
SELECT * FROM V$LICENSE; -- 基本许可信息
SELECT * FROM V$RESERVED_WORDS ORDER BY 1; -- ORACLE 保留字

事实上,Oracle 提供了很多动态性能视图,其中有一个视图是V$FIXED_TABLE,该视图中包含数据库中的所有动态性能表、视图和派生表的信息。其中部分V$表 (例如V$ROLLNAME) 是指真正的表, 因此没有列出。

2.2、运用动态性能视图

SELECT * FROM V$VERSION; -- 数据库中核心库组件的版本号,每个组件占一行
SELECT * FROM V$OPTION; -- 数据库中功能选项,已安装的则 value 为 true
SELECT * FROM V$PARAMETER; -- 有关会话当前有效的初始化参数的信息,isdefault=true 表示当前值是默认值

查看有问题的语句的查询计划

SELECT * FROM DBA_HIST_SQL_PLAN t;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_AWR(\'cfz686a6qp0kg\'));

检查用户当前操作极其使用的资源

SELECT t1.sid,t1.username,t2.sql_text FROM V$SESSION t1,V$SQLTEXT t2
WHERE t1.sql_address=t2.address AND t1.sql_hash_value=t2.hash_value ORDER BY t1.username,t1.sid,t2.piece;

查询 CUP 时间超过 2000000 微妙的语句

SELECT t.sql_text,t.executions FROM V$SQLSTATS t WHERE t.cpu_time>2000000;

查询最近 7 天,磁盘增量读取数高于 10 万的语句

SELECT t1.snap_id,t1.disk_reads_delta,t1.disk_reads_total,t1.executions_delta,t1.executions_total,
  t1.disk_reads_delta/t1.executions_delta rds_exec_ratio,t1.sql_id,t2.sql_text
FROM DBA_HIST_SQLSTAT t1,DBA_HIST_SQLTEXT t2
WHERE t1.sql_id=t2.sql_id AND t1.disk_reads_delta>100000
ORDER BY t1.disk_reads_delta DESC;

查询磁盘读取数大于 10 万的语句,disk_reads 磁盘读取数,executions 执行次数

SELECT t2.username,t1.disk_reads,t1.executions,t1.disk_reads/t1.executions rds_exec_ratio,t1.sql_text,t1.elapsed_time,t1.cpu_time
FROM V$SQLAREA t1,DBA_USERS t2
WHERE t1.parsing_user_id=t2.user_id AND t1.disk_reads>100000
ORDER BY t1.disk_reads DESC;

查询缓冲区数量最多的 10 个语句

WITH t2 AS(
SELECT t1.buffer_gets,
  RANK() OVER(ORDER BY t1.buffer_gets DESC) AS rank_buf_gets,
  TO_CHAR(100*RATIO_TO_REPORT(buffer_gets) OVER(),\'999.99\') rate_buf_gets,
  t1.address,t1.sql_text
FROM V$SQL t1)
SELECT t2.* FROM t2 WHERE t2.rank_buf_gets<=10;

测定数据的命中率

SELECT 1-(SUM(DECODE(t.name,\'physical reads\',VALUE,0))/(SUM(DECODE(t.name,\'db block gets\',VALUE,0))+
(SUM(DECODE(t.name,\'consistent gets\',VALUE,0))))) read_hit_ratio FROM V$SYSSTAT t;

测定数据字典的命中率

SELECT SUM(gets),SUM(getmisses),(1-(SUM(getmisses)/(SUM(gets)+SUM(getmisses))))*100 hitrate FROM V$ROWCACHE;

测定共享 SQL 和 PL/SQL 的命中率

SELECT SUM(t.pins) executions,SUM(t.pinhits) hits,((SUM(t.pinhits)/SUM(t.pins))*100) pinhitratio,
SUM(reloads) misses,((SUM(t.pins)/(SUM(t.pins)+SUM(t.reloads)))*100) relhitratio FROM V$LIBRARYCACHE t;

下面的这个值应该大于 15

SELECT t.sql_id,COUNT(1) bind_count FROM V$SQL_BIND_CAPTURE t
WHERE t.child_number=0 GROUP BY t.sql_id HAVING COUNT(1)>20 ORDER BY COUNT(1);

确定需要固定的 PL/SQL 对象,搜索那些需要空间大于100KB的对象

SELECT t.name,t.sharable_mem FROM V$DB_OBJECT_CACHE t WHERE t.sharable_mem>100000
AND t.type IN(\'PACKAGE\',\'PACKAGE BODY\',\'FUNCTION\',\'PROCEDURE\') AND t.kept=\'NO\';

查询数据文件使用情况

SELECT t1.file#,t1.name,t1.status,t1.bytes,t2.phyrds,t2.phyblkrd,t2.phywrts,t2.phyblkwrt
FROM V$DATAFILE t1,V$FILESTAT t2 WHERE t1.file#=t2.file#;

查询表空间的使用情况

SELECT t1.tablespace_name,t1.file_name,t1.bytes,t2.phyrds,t2.phyblkrd,t2.phywrts,t2.phyblkwrt
FROM DBA_DATA_FILES t1,V$FILESTAT t2 WHERE t1.file_id=t2.file#;

查询表空间碎片化程度

SELECT t.tablespace_name,SUM(t.bytes) sum_bytes,MAX(t.bytes) max_bytes,COUNT(t.block_id) cnt
FROM DBA_FREE_SPACE t GROUP BY t.tablespace_name;

查询碎片化程度最高于 5 的存储对象

WITH t2 AS(
  SELECT t1.segment_type,t1.segment_name,COUNT(1) OVER(PARTITION BY t1.segment_name) cnt
  FROM DBA_SEGMENTS t1
)
SELECT DISTINCT t2.* FROM t2 WHERE t2.cnt>5;

3、死锁

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象——死锁。

3.1、定位死锁

1、定位造成死锁的用户和机器

SELECT t1.username,t1.lockwait,t1.status,t1.machine,t1.program
FROM V$SESSION t1 WHERE EXISTS(SELECT 1 FROM V$LOCKED_OBJECT t2 WHERE t1.sid=t2.session_id);

用 DBA 用户执行如下语句,如果能查询到数据,就说明数据库中存在死锁。上述语句中的字段说明:

  • username:发生死锁的数据库用户。
  • lockwait:死锁等待。有内容的就是被死锁的,没有内容的就是造成死锁的。
  • status:死锁状态。ACTIVE 状态表示被死锁。
  • machine:死锁语句所在的机器。
  • program:产生死锁的那个应用程序名称。

2、定位造成死锁的语句

-- 用 DBA 用户执行以下语句,可以查看到被锁的语句(后执行的语句被先执行的语句锁住)
SELECT t1.sql_id,t1.sql_text FROM V$SQL t1 WHERE t1.hash_value IN(
  SELECT t2.sql_hash_value FROM V$SESSION t2 WHERE t2.sid IN(
    SELECT t3.session_id FROM V$LOCKED_OBJECT t3
  )
);

-- 另一种写法,可以查到更多信息
SELECT t2.username,t2.serial#,t1.id1,t3.sql_text FROM V$LOCK t1,V$SESSION t2,V$SQLTEXT t3
WHERE t1.kaddr=t2.lockwait AND t2.sql_address=t3.address AND t2.sql_hash_value=t3.hash_value;

-- 查询数据库中死锁相关信息
SELECT t1.owner,t1.object_name 被锁对象名,t2.session_id,t2.oracle_username 登录用户,
t2.os_user_name 登录机器用户名,t2.process,t2.locked_mode 锁模式,t3.machine 机器名,
t3.terminal 终端用户名,t3.logon_time 登录数据库时间,t3.status,t3.sid,t3.serial#,t3.program
FROM all_objects t1,v$locked_object t2,v$session t3
WHERE t1.object_id=t2.object_id AND t2.process=t3.process
ORDER BY 1,2;

3.2、解锁方法

一般来说只要将产生死锁的语句提交就可以解锁了,但实际上用户往往不知道死锁是那里造成的。当然迫不得以的话,将程序关闭并重新启动肯定是可以解锁的。下面介绍一种常见的解锁方法(即直接把有问题的会话 Kill 掉):

1、定位死锁的进程

SELECT t2.username,t1.object_id,t1.session_id,t2.serial#,t1.oracle_username,t1.os_user_name,t2.program,t2.terminal
FROM V$LOCKED_OBJECT t1,V$SESSION t2 WHERE t1.session_id=t2.sid;

2、Kill 掉这个死锁的进程

ALTER SYSTEM KILL SESSION \'[sid/session_id],[serial#]\'; -- session_id 和 serial# 的值来自第一步的执行结果

3.3、强制删除已连接用户

当一个用户被连接之后,就无法直接删除该用户了。如果要强制删除,就得先 Kill 掉会话进程。强制删除一个已连接用户的步骤:

1、查询该用户的会话信息,得到用户的 sid 和 serial#。

SELECT t.sid,t.serial# FROM V$SESSION t WHERE t.username=\'user_name\';

2、Kill 掉该用户的所有会话进程。

ALTER SYSTEM KILL SESSION \'sid, serial#\';

3、删除用户及用户对象。

DROP USER user_name CASCADE;

4、总结

本文第一节介绍了 Oracle 中的数据字典及常见数据字典和简单应用;第二节主要讲述了 Oracle 中的死锁,着重介绍了如何定位死锁及如何解锁。

Oracle 中的数据字典非常多,正常人肯定是无法全部记住的,其实也没必要记住,只需要记住 DICTIONARY 视图就可以了,因为这个视图中记录了所有的数据字典的名称和描述,就像是一个数据字典的字典。所以当我们需要查询数据字典中的信息却又不知道该查那个数据字典时,就可以到 DICTIONARY 视图里找,该视图还有个同名词 DICT。

本文链接http://www.cnblogs.com/hanzongze/p/Oracle-Dictionary.html
版权声明:本文为博客园博主 韩宗泽 原创,作者保留署名权!欢迎通过转载、演绎或其它传播方式来使用本文,但必须在明显位置给出作者署名和本文链接!本人初写博客,水平有限,若有不当之处,敬请批评指正,谢谢!

 

以上是关于数据字典死锁的主要内容,如果未能解决你的问题,请参考以下文章

sqlserver-处理死锁

13 个非常有用的 Python 代码片段

ASP.NET 挂起 - 通用字典并发问题导致 GC 死锁

Python snippet(代码片段)

Python代码阅读(第19篇):合并多个字典

Python代码阅读(第26篇):将列表映射成字典