Oracle查询存在外键约束但未创建对应索引的情况
1.Oracle提供的脚本
如果要求管控严格,可以考虑使用Oracle官方提供的脚本。
- Script to Check for Foreign Key Locking Issues for a Specific User (Doc ID 1019527.6)
但也要注意,该脚本是查询当前连接用户存在外键约束但未创建对应索引的情况,且创建了表ck_log的,脚本最开始还会先删除表ck_log,如果业务不允许创建与业务无关的表,甚至业务可能有这种名字的表就一定要注意了!
vi tfsfkchk.sql
SET ECHO off
REM NAME: TFSFKCHLK.SQL
REM USAGE:"@path/tfsfkchk"
REM --------------------------------------------------------------------------
REM REQUIREMENTS:
REM None -- checks only the USER_ views
REM --------------------------------------------------------------------------
REM This file checks the current users Foreign Keys to make sure of the
REM following:
REM
REM 1) All the FK columns are have indexes to prevent a possible locking
REM problem that can slow down the database.
REM
REM 2) Checks the ORDER OF THE INDEXED COLUMNS. To prevent the locking
REM problem the columns MUST be index in the same order as the FK is
REM defined.
REM
REM 3) If the script finds and miss match the script reports the correct
REM order of columns that need to be added to prevent the locking
REM problem.
REM
REM
REM
REM -------------------------------------------------------------------------
REM Main text of script follows:
drop table ck_log;
create table ck_log (
LineNum number,
LineMsg varchar2(2000));
declare
t_CONSTRAINT_TYPE user_constraints.CONSTRAINT_TYPE%type;
t_CONSTRAINT_NAME USER_CONSTRAINTS.CONSTRAINT_NAME%type;
t_TABLE_NAME USER_CONSTRAINTS.TABLE_NAME%type;
t_R_CONSTRAINT_NAME USER_CONSTRAINTS.R_CONSTRAINT_NAME%type;
tt_CONSTRAINT_NAME USER_CONS_COLUMNS.CONSTRAINT_NAME%type;
tt_TABLE_NAME USER_CONS_COLUMNS.TABLE_NAME%type;
tt_COLUMN_NAME USER_CONS_COLUMNS.COLUMN_NAME%type;
tt_POSITION USER_CONS_COLUMNS.POSITION%type;
tt_Dummy number;
tt_dummyChar varchar2(2000);
l_Cons_Found_Flag VarChar2(1);
Err_TABLE_NAME USER_CONSTRAINTS.TABLE_NAME%type;
Err_COLUMN_NAME USER_CONS_COLUMNS.COLUMN_NAME%type;
Err_POSITION USER_CONS_COLUMNS.POSITION%type;
tLineNum number;
cursor UserTabs is
select table_name
from user_tables
order by table_name;
cursor TableCons is
select CONSTRAINT_TYPE,
CONSTRAINT_NAME,
R_CONSTRAINT_NAME
from user_constraints
where OWNER = USER
and table_name = t_Table_Name
and CONSTRAINT_TYPE = 'R'
order by TABLE_NAME, CONSTRAINT_NAME;
cursor ConColumns is
select CONSTRAINT_NAME,
TABLE_NAME,
COLUMN_NAME,
POSITION
from user_cons_columns
where OWNER = USER
and CONSTRAINT_NAME = t_CONSTRAINT_NAME
order by POSITION;
cursor IndexColumns is
select TABLE_NAME,
COLUMN_NAME,
POSITION
from user_cons_columns
where OWNER = USER
and CONSTRAINT_NAME = t_CONSTRAINT_NAME
order by POSITION;
DebugLevel number := 99; -- >>> 99 = dump all info`
DebugFlag varchar(1) := 'N'; -- Turn Debugging on
t_Error_Found varchar(1);
begin
tLineNum := 1000;
open UserTabs;
LOOP
Fetch UserTabs into t_TABLE_NAME;
t_Error_Found := 'N';
exit when UserTabs%NOTFOUND;
-- Log current table
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, NULL );
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Checking Table '||t_Table_Name);
l_Cons_Found_Flag := 'N';
open TableCons;
LOOP
FETCH TableCons INTO t_CONSTRAINT_TYPE,
t_CONSTRAINT_NAME,
t_R_CONSTRAINT_NAME;
exit when TableCons%NOTFOUND;
if ( DebugFlag = 'Y' and DebugLevel >= 99 )
then
begin
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Found CONSTRAINT_NAME = '|| t_CONSTRAINT_NAME);
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Found CONSTRAINT_TYPE = '|| t_CONSTRAINT_TYPE);
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Found R_CONSTRAINT_NAME = '|| t_R_CONSTRAINT_NAME);
commit;
end;
end if;
open ConColumns;
LOOP
FETCH ConColumns INTO
tt_CONSTRAINT_NAME,
tt_TABLE_NAME,
tt_COLUMN_NAME,
tt_POSITION;
exit when ConColumns%NOTFOUND;
if ( DebugFlag = 'Y' and DebugLevel >= 99 )
then
begin
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, NULL );
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Found CONSTRAINT_NAME = '|| tt_CONSTRAINT_NAME);
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Found TABLE_NAME = '|| tt_TABLE_NAME);
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Found COLUMN_NAME = '|| tt_COLUMN_NAME);
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Found POSITION = '|| tt_POSITION);
commit;
end;
end if;
begin
select 1 into tt_Dummy
from user_ind_columns
where TABLE_NAME = tt_TABLE_NAME
and COLUMN_NAME = tt_COLUMN_NAME
and COLUMN_POSITION = tt_POSITION;
if ( DebugFlag = 'Y' and DebugLevel >= 99 )
then
begin
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Row Has matching Index' );
end;
end if;
exception
when Too_Many_Rows then
if ( DebugFlag = 'Y' and DebugLevel >= 99 )
then
begin
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Row Has matching Index' );
end;
end if;
when no_data_found then
if ( DebugFlag = 'Y' and DebugLevel >= 99 )
then
begin
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'NO MATCH FOUND' );
commit;
end;
end if;
t_Error_Found := 'Y';
select distinct TABLE_NAME
into tt_dummyChar
from user_cons_columns
where OWNER = USER
and CONSTRAINT_NAME = t_R_CONSTRAINT_NAME;
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum, 'Changing data in table '||tt_dummyChar
||' will lock table ' ||tt_TABLE_NAME);
commit;
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum,'Create an index on table '||tt_TABLE_NAME
||' with the following columns to remove lock problem');
open IndexColumns ;
loop
Fetch IndexColumns into Err_TABLE_NAME,
Err_COLUMN_NAME,
Err_POSITION;
exit when IndexColumns%NotFound;
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum,'Column = '||Err_COLUMN_NAME||' ('||Err_POSITION||')');
end loop;
close IndexColumns;
end;
end loop;
commit;
close ConColumns;
end loop;
if ( t_Error_Found = 'N' )
then
begin
tLineNum := tLineNum + 1;
insert into ck_log ( LineNum, LineMsg ) values
( tLineNum,'No foreign key errors found');
end;
end if;
commit;
close TableCons;
end loop;
commit;
end;
/
select LineMsg
from ck_log
where LineMsg NOT LIKE 'Checking%' AND
LineMsg NOT LIKE 'No foreign key%'
order by LineNum
/
2.网络搜索到的脚本
这个是网络搜到的脚本,实测可用,也不需要建立中间表,但是也只能查询当前连接用户,对于DBA而言,也不够方便。
--外键无索引:(当前登陆用户)
column con format a20 word_wrapped
column idx format a20 word_wrapped
column table_name format a30 word_wrapped
select decode( b.table_name, NULL, '****', 'ok' ) Status,
a.table_name, a.columns con, b.columns idx
from
( select substr(a.table_name,1,30) table_name,
substr(a.constraint_name,1,30) constraint_name,
max(decode(position, 1, substr(column_name,1,30),NULL)) ||
max(decode(position, 2,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 3,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 4,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 5,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 6,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 7,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 8,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 9,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,10,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,11,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,12,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,13,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,14,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,15,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,16,', '||substr(column_name,1,30),NULL)) columns
from user_cons_columns a, user_constraints b
where a.constraint_name = b.constraint_name
and b.constraint_type = 'R'
group by substr(a.table_name,1,30), substr(a.constraint_name,1,30) ) a,
( select substr(table_name,1,30) table_name, substr(index_name,1,30) index_name,
max(decode(column_position, 1, substr(column_name,1,30),NULL)) ||
max(decode(column_position, 2,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 3,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 4,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 5,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 6,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 7,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 8,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 9,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,10,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,11,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,12,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,13,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,14,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,15,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,16,', '||substr(column_name,1,30),NULL)) columns
from user_ind_columns
group by substr(table_name,1,30), substr(index_name,1,30) ) b
where a.table_name = b.table_name (+)
and b.columns (+) like a.columns || '%'
/
3.改为可以指定用户的脚本
这个是修改后的脚本,主要就是将user_*的视图改为dba_*,然后手工输入指定对应的业务用户,从而方便DBA查询指定用户下的情况。
vi check_fk_info.sql
--外键无索引:(指定要查询的用户)
column con format a20 word_wrapped
column idx format a20 word_wrapped
column table_name format a30 word_wrapped
select decode( b.table_name, NULL, '****', 'ok' ) Status,
a.table_name, a.columns con, b.columns idx
from
( select substr(a.table_name,1,30) table_name,
substr(a.constraint_name,1,30) constraint_name,
max(decode(position, 1, substr(column_name,1,30),NULL)) ||
max(decode(position, 2,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 3,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 4,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 5,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 6,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 7,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 8,', '||substr(column_name,1,30),NULL)) ||
max(decode(position, 9,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,10,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,11,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,12,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,13,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,14,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,15,', '||substr(column_name,1,30),NULL)) ||
max(decode(position,16,', '||substr(column_name,1,30),NULL)) columns
from dba_cons_columns a, dba_constraints b
where a.constraint_name = b.constraint_name
and b.constraint_type = 'R'
and a.owner = upper('&owner')
group by substr(a.table_name,1,30), substr(a.constraint_name,1,30) ) a,
( select substr(table_name,1,30) table_name, substr(index_name,1,30) index_name,
max(decode(column_position, 1, substr(column_name,1,30),NULL)) ||
max(decode(column_position, 2,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 3,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 4,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 5,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 6,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 7,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 8,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position, 9,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,10,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,11,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,12,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,13,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,14,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,15,', '||substr(column_name,1,30),NULL)) ||
max(decode(column_position,16,', '||substr(column_name,1,30),NULL)) columns
from dba_ind_columns
where INDEX_OWNER = upper('&index_owner')
group by substr(table_name,1,30), substr(index_name,1,30) ) b
where a.table_name = b.table_name (+)
and b.columns (+) like a.columns || '%'
/
4.测试脚本使用
比如使用修改过的脚本,查询业务SCOTT用户下的情况:
sys@DEMO> @check_fk_info.sql
Enter value for owner: scott
old 25: and a.owner = upper('&owner')
new 25: and a.owner = upper('scott')
Enter value for index_owner: scott
old 45: where INDEX_OWNER = upper('&index_owner')
new 45: where INDEX_OWNER = upper('scott')
STAT TABLE_NAME CON IDX
---- ------------------------------ -------------------- --------------------
**** EMP DEPTNO
sys@DEMO>
上面就是查询到EMP表在DEPTNO列上存在外键约束,且没有索引,如果需要进一步查看表的建表语句,可以这样查询:
--查询建表语句;
sys@DEMO>
set long 999999 pages 1000
select dbms_metadata.get_ddl('TABLE','EMP','SCOTT') from dual;
DBMS_METADATA.GET_DDL('TABLE','EMP','SCOTT')
--------------------------------------------------------------------------------
CREATE TABLE "SCOTT"."EMP"
( "EMPNO" NUMBER(4,0),
"ENAME" VARCHAR2(10),
"JOB" VARCHAR2(9),
"MGR" NUMBER(4,0),
"HIREDATE" DATE,
"SAL" NUMBER(7,2),
"COMM" NUMBER(7,2),
"DEPTNO" NUMBER(2,0),
CONSTRAINT "PK_EMP" PRIMARY KEY ("EMPNO")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS" ENABLE,
CONSTRAINT "FK_DEPTNO" FOREIGN KEY ("DEPTNO")
REFERENCES "SCOTT"."DEPT" ("DEPTNO") ENABLE
) SEGMENT CREATION IMMEDIATE
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
TABLESPACE "USERS"
Oracle的规范是建议在业务用户下表存在外键约束的,都要在对应列上建立相应的索引。实际也遇到过很多客户的生产环境因外键没有创建索引而导致一些死锁和性能相关的问题。
Oracle查询存在外键约束但未创建对应索引的情况的更多相关文章
- Sql语句中两个比较迷糊的概念:“连接查询” 与 “外键约束”
Sql语句中两个比较迷糊的概念:“连接查询” 与 “外键约束 Sql 中的连接查询:就是为了避免笛卡尔积,因为涉及到多表查询的化,不使用连接查询,会先将多个互相乘,求出笛卡尔积,然后在在里面查询符合的 ...
- oracle 查看主外键约束
select a.constraint_name, a.table_name, b.constraint_name from user_constraints a, user_constraints ...
- MySQL数据库 : 查询语句,连接查询及外键约束
查询指定字段 select 字段1,字段2 from 表名; 消除重复行(重复指的是结果集中的所有完全重复行) select distinct 字段1,字段2.. ...
- Oracle 外键约束
本文讨论一下Oracle中的外键约束问题,以及和DB2中的小不同. 首先创建测试环境. -- 创建测试主表. ID 是主键. CREATE TABLE test_main ( id INT, valu ...
- Oracle数据库,非空约束、主键约束、外键约束、唯一约束
非空约束:设置列时,可为空默认可为空,去掉对号之后设置数据不可为空: 唯一约束:在键中设置,唯一约束名称.类型Unique.列名:设置应用完成之后,此列数据具有唯一性:即数据不可重复(类型:Uniqu ...
- 数据库 SQL 外键约束 多表查询
多表设计与多表查询 1.外键约束 表是用来保存现实生活中的数据的,而现实生活中数据和数据之间往往具有一定的关系,我们在使用表来存储数据时,可以明确的声明表和表之前的依赖关系,命令数据库来 ...
- python--MySql(外键约束、多表查询(*****))
两张表之间的关系: 一对一(两张表可以合并成一张表) 一对一用的比较少,多对一对外键设置unique约束可以实现一对一 一对多(例如:每一个班主任会对应多个学生 , 而每个学生只能对应一个班主任) 多 ...
- MySQL数据库删除数据(有外键约束)
在MySQL中删除一张表或一条数据的时候,出现有外键约束的问题,于是就去查了下方法: SELECT @@FOREIGN_KEY_CHECKS; 查询当前外键约束是否打开 ; 设置为1的时候外键约束是打 ...
- Oracle开发 之 主-外键约束FK及约束的修改
试验环境: 1)数据库版本:oracle 11.2.0.4 2)建表脚本:以scott的dept及emp表为基础. 父表:dept -- Create table create table DEPT ...
- sql操作数据库(3)-->外键约束、数据库表之间的关系、三大范式、多表查询、事务
外键约束 在新表中添加外键约束语法: constraint 外键约束名称 foreign key(外键的字段名称) references 主表表名(主键字段名) 在已有表中添加外键约束:alter t ...
随机推荐
- 四、swift大对象--静态态大对象
系列导航 一.swift对象存储环境搭建 二.swift添加存储策略 三.swift大对象--动态大对象 四.swift大对象--静态态大对象 五.java操作swift对象存储(官网样例) 六.ja ...
- linux驱动开发中copy_from_user open read write等常用函数总结
目录 open read write copy_to_user copy_from_user open 函数定义: int open( const char * pathname, int flags ...
- freeswitch配置SBC的方案
概述 freeswitch 是一款好用的开源软交换平台. 但是,fs不是专为SBC而开发的,所以需要做一些定制化的配置和开发. 本文主要介绍如何利用fs的基本功能配置一个简单的SBC方案,满足一般化需 ...
- Object.defineProperty()实现双向数据绑定
<div id="app"> <input type="text" name="txt" id="txt&quo ...
- asp.net core之实时应用
本文将介绍ASP.NET Core SignalR,这是一个强大的实时通信库,用于构建实时.双向通信应用程序.我们将探讨SignalR的基本概念.架构和工作原理,并提供一些示例代码来帮助读者更好地理解 ...
- UPF - Power Intent Basic
Mainstream Low Power techniques Low Vth - 阈值电压比较低,翻转时间小,漏电流比较大,功耗大,速度快 High Vth - 阈值电压比较高,翻转时间长,漏电流比 ...
- [转帖]Oracle nvarchar2存储特殊字符乱码问题
https://www.cnblogs.com/PiscesCanon/p/15157506.html 这个问题研究了一天多,终于搞定了. 起因是业务需要存特殊字符'ø'到varchar2的字段中出现 ...
- [转帖]CentOS-7-x86_64-DVD-2009 rpm包列表(centos7.9)
https://www.cnblogs.com/hiyang/p/14803391.html 文件数 4071 个,共3.8G 复制389-ds-base-1.3.10.2-6.el7.x86_64. ...
- [转帖]Percolator - 分布式事务的理解与分析
https://zhuanlan.zhihu.com/p/261115166 Percolator - 分布式事务的理解与分析 概述 一个web页面能不能被Google搜索到,取决于它是否被Googl ...
- [转帖]echo 输出不换行-e \c
http://www.my889.com/i/1952 在shell中,echo输出会自动换行.有时候在循环中不希望echo输出换行.代码实现如下: 1 echo -e " \c" ...