Lorsque les procédures stockées sont appelées sous les locataires Oracle et OB Oracle, les performances des deux sont incohérentes, ce qui entraîne un épissage incomplet du texte SQL obtenu, ce qui affecte les tests fonctionnels du côté métier. Cet article effectuera des tests et des vérifications pertinents sur ce problème.
Auteur : Zhao Liming, membre de l'équipe DBA MySQL d'Aikesheng. Il connaît les bases de données telles qu'Oracle et MySQL. Il est doué pour diagnostiquer les problèmes de performances des bases de données et analyser les problèmes de transaction et de verrouillage. Il est responsable de la gestion des opérations quotidiennes et maintenance du client MySQL et de la plate-forme DMP auto-développée par notre entreprise. Question, je suis très intéressé par les technologies liées aux bases de données open source.
Produit par la communauté open source Aikeson. Le contenu original ne peut être utilisé sans autorisation. Veuillez contacter l'éditeur et indiquer la source pour la réimpression.
Cet article compte environ 3 100 mots et sa lecture devrait prendre 10 minutes.
arrière-plan
Récemment, un client a rencontré un problème. Lorsque les procédures stockées étaient appelées sous les locataires Oracle et OB Oracle, les performances des deux étaient incohérentes, ce qui entraînait un épissage incomplet du texte SQL obtenu, ce qui affectait les tests fonctionnels du côté commercial.
La logique de la procédure stockée du client n'est pas compliquée : elle interroge simplement la vue système user_tab_columns
pour obtenir le nom de la table de l'utilisateur, puis effectue un épissage SQL pour compléter la logique métier suivante.
Cet article effectuera des tests et des vérifications pertinents sur ce problème.
Récurrence du problème
Validation dans l'environnement Oracle
-- 创建测试用户并赋权
[root@localhost ~]# sqlplus / as sysdba
SQL> create user u1 identified by u1;
User created.
SQL> create user u2 identified by u2;
User created.
SQL> grant connect,resource to u1;
Grant succeeded.
SQL> grant create procedure to u1;
Grant succeeded.
SQL> grant connect,resource to u2;
Grant succeeded.
SQL> grant create synonym to u2;
Grant succeeded.
SQL> grant select any table to u2;
Grant succeeded.
-- 创建测试表并赋权
SQL> conn u1/u1
Connected.
SQL> create table t1(id int);
Table created.
SQL> insert into t1(id) values(1);
1 row created.
-- 创建表的同义词
SQL> conn u2/u2
Connected.
SQL> create synonym t1 for u1.t1;
Synonym created.
SQL> set lin 200
SQL> col owner for a5
SQL> col table_owner for a5
SQL> col db_link for a10
SQL> select * from all_synonyms where owner='U2';
OWNER SYNONYM_NAME TABLE TABLE_NAME DB_LINK
----- ------------------------------ ----- ------------------------------ ----------
U2 T1 U1 T1
-- 创建存储过程并赋权
SQL> conn u1/u1
Connected.
SQL> create or replace procedure proc_case1 as
v_str varchar2(10);
begin
select table_name into v_str from user_tab_columns where table_name='T1';
dbms_output.put_line(v_str);
end;
/ 2 3 4 5 6 7
Procedure created.
SQL> grant execute on proc_case1 to u2;
Grant succeeded.
-- 创建存储过程同义词
SQL> conn u2/u2
Connected.
SQL> create synonym proc_case1 for u1.proc_case1;
Synonym created.
SQL> select * from all_synonyms where owner='U2';
OWNER SYNONYM_NAME TABLE TABLE_NAME DB_LINK
----- ------------------------------ ----- ------------------------------ ----------
U2 PROC_CASE1 U1 PROC_CASE1
U2 T1 U1 T1
-- 验证
SQL> conn u1/u1
Connected.
SQL> select * from t1;
ID
----------
1
SQL> set serveroutput on;
SQL> call proc_case1();
T1
Call completed.
SQL> conn u2/u2
Connected.
SQL> select * from t1;
ID
----------
1
SQL> set serveroutput on;
SQL> call proc_case1();
T1
Call completed.
SQL>
On peut voir que dans Oracle, qu'il s'agisse d'un utilisateur u1 ou u2, le nom de la table peut être renvoyé correctement lors de l'appel de la procédure stockée, indiquant que les résultats de retour user_tab_columns
des deux vues de requête sont cohérents, ce qui est également conforme aux attentes.
Validation en environnement OB Oracle
-- 创建测试用户并赋权
SYS[SYS]> create user u1 identified by u1;
Query OK, 0 rows affected (0.04 sec)
SYS[SYS]> create user u2 identified by u2;
Query OK, 0 rows affected (0.04 sec)
SYS[SYS]> grant connect,resource to u1;
Query OK, 0 rows affected (0.04 sec)
SYS[SYS]> grant create procedure to u1;
Query OK, 0 rows affected (0.03 sec)
SYS[SYS]> grant connect,resource to u2;
Query OK, 0 rows affected (0.05 sec)
SYS[SYS]> grant create synonym to u2;
Query OK, 0 rows affected (0.03 sec)
SYS[SYS]> grant select any table to u2;
Query OK, 0 rows affected (0.03 sec)
-- 创建测试表并赋权
SYS[SYS]> conn u1
Connection id: 269006
Current database: U1
SYS[U1]> create table t1(id int);
Query OK, 0 rows affected (0.21 sec)
SYS[U1]> insert into t1(id) values(1);
Query OK, 1 row affected (0.03 sec)
SYS[U1]> commit;
Query OK, 0 rows affected (0.01 sec)
-- 创建表的同义词
SYS[U1]> conn u2
Connection id: 50837
Current database: U2
SYS[U2]> create synonym t1 for u1.t1;
Query OK, 0 rows affected (0.05 sec)
SYS[U2]> select * from all_synonyms where owner='U2';
+-------+--------------+-------------+------------+---------+
| OWNER | SYNONYM_NAME | TABLE_OWNER | TABLE_NAME | DB_LINK |
+-------+--------------+-------------+------------+---------+
| U2 | T1 | U1 | T1 | NULL |
+-------+--------------+-------------+------------+---------+
2 rows in set (0.01 sec)
-- 创建存储过程并赋权
SYS[U2]> conn u1
Connection id: 269078
Current database: U1
SYS[U1]> create or replace procedure proc_case1 as
-> v_str varchar2(10);
-> begin
-> select table_name into v_str from user_tab_columns where table_name='T1';
-> dbms_output.put_line(v_str);
-> end;
-> /
Query OK, 0 rows affected (0.17 sec)
SYS[U1]> grant execute on proc_case1 to u2;
Query OK, 0 rows affected (0.06 sec)
-- 创建存储过程同义词
SYS[U1]> conn u2
Connection id: 50896
Current database: U2
SYS[U2]> create synonym proc_case1 for u1.proc_case1;
Query OK, 0 rows affected (0.05 sec)
SYS[U2]> select * from all_synonyms where owner='U2';
+-------+--------------+-------------+------------+---------+
| OWNER | SYNONYM_NAME | TABLE_OWNER | TABLE_NAME | DB_LINK |
+-------+--------------+-------------+------------+---------+
| U2 | PROC_CASE1 | U1 | PROC_CASE1 | NULL |
| U2 | T1 | U1 | T1 | NULL |
+-------+--------------+-------------+------------+---------+
2 rows in set (0.01 sec)
-- 验证
SYS[U2]> conn u1
Connection id: 269134
Current database: U1
SYS[U1]> select * from t1;
+------+
| ID |
+------+
| 1 |
+------+
1 row in set (0.01sec)
SYS[U1]> set serveroutput on;
Query OK, 0 rows affected (0.41 sec)
SYS[U1]> call proc_case1();
Query OK, 0 rows affected (0.21 sec)
SYS[U1]> select table_name,column_name from user_tab_columns;
+------------+-------------+
| TABLE_NAME | COLUMN_NAME |
+------------+-------------+
| C | NAME |
| C | ADDRESS |
+------------+-------------+
2 rows in set (0.08 sec)
En fait, quelques indices peuvent être trouvés ici.Bien que les utilisateurs puissent être commutés via conn dans OB et que les utilisateurs commutés puissent également accéder à leurs propres objets, lors de l'accès à des vues telles que USER_, les résultats renvoyés sont différents de ceux d'Oracle.
Lorsque l'utilisateur u1 interroge user_tab_columns
la table, il ne peut voir que les tables sous l'utilisateur SYS (la table C a été créée par l'utilisateur SYS), donc la procédure stockée ne peut pas renvoyer le nom de la table T1 et le résultat de la requête est vide.
-- 直连 u1 用户验证
U1[U1]> select * from t1;
+------+
| ID |
+------+
| 1 |
+------+
1 row in set (0.01sec)
U1[U1]> set serveroutput on;
Query OK, 0 rows affected (0.02sec)
U1[U1]> call proc_case1();
Query OK, 0 rows affected (0.08sec)
T1
U1[U1]>
-- 直连 u2 用户进行验证
U2[U2]> select * from t1;
+------+
| ID |
+------+
| 1 |
+------+
1 row in set (0.03sec)
U2[U2]> set serveroutput on;
Query OK, 0 rows affected (0.44 sec)
U2[U2]> call proc_case1();
Query OK, 0 rows affected (0.43 sec)
U2[U2]> select * from user_tab_columns;
Empty set (0.08 sec)
# 同样地,u2 也无法从 user_tab_columns 视图中查询到 u1 创建的表,调用存储过程返回结果为空
-- 将 user_tab_columns 替换成 all_tab_columns 视图
U2[U2]> select table_name,column_name from all_tab_columns where owner='U1';
+------------+-------------+
| TABLE_NAME | COLUMN_NAME |
+------------+-------------+
| T1 | ID |
+------------+-------------+
1 row in set (0.08 sec)
U2[U2]> create or replace procedure proc_case2 as
-> v_str varchar2(10);
-> begin
-> select table_name into v_str from all_tab_columns where table_name='T1' and owner='U1';
-> dbms_output.put_line(v_str);
-> end;
-> /
Query OK, 0 rows affected (0.17ec)
U2[U2]> call proc_case2();
Query OK, 0 rows affected (0.16ec)
T1
U2[U2]>
-- 将 SELECT ANY TABLE 权限回收
SYS[SYS]> revoke select any table from u2;
Query OK, 0 rows affected (0.03 sec)
U2[U2]> select table_name,column_name from all_tab_columns where owner='U1';
Empty set (0.05 sec)
U2[U2]> set serveroutput on;
Query OK, 0 rows affected (0.01 sec)
U2[U2]> call proc_case2();
Query OK, 0 rows affected (0.05 sec)
Lorsque l'utilisateur u2 ne dispose pas de l'autorisation système SELECT ANY TABLE, même si all_tab_columns
la vue est interrogée, les informations sur les tables créées par d'autres utilisateurs ne peuvent pas être obtenues.
Dépanner les objets associés qui appellent les vues système
Objet PL
Objets PL, tels que fonctions, procédures stockées, etc.
-- dba_source 视图中存放了各种 PL 对象的定义
SQL> select count(*),type from dba_source group by type;
COUNT(*) TYPE
---------- ------------
152202 PROCEDURE
89318 PACKAGE
31504 PACKAGE BODY
1276 TYPE BODY
2210 TRIGGER
3895 FUNCTION
7 JAVA SOURCE
12338 TYPE
8 rows selected.
-- 创建测试存储过程(大小写各1个)
SQL> CREATE OR REPLACE PROCEDURE PROC_1 IS
V_N NUMBER :=0;
BEGIN
SELECT COUNT(*) INTO V_N FROM USER_TAB_COLUMNS;
END;
/ 2 3 4 5 6
Procedure created.
SQL> create or replace procedure proc_2 is
v_n number :=0;
begin
select count(*) into v_n from user_tab_columns;
end;
/ 2 3 4 5 6
Procedure created.
-- 查询常用系统视图名(此处只列举了几个与表相关的视图)
select owner,object_name,object_type from dba_objects where owner='SYS' and (object_name like 'USER_PART_%' or object_name like 'USER_T%' or object_name like 'ALL_PART_%' or object_name like 'ALL_T%' or object_name like 'DBA_PART_%' or object_name like 'DBA_T%');
-- 根据上一步获取到的系统视图名,通过模糊搜索,即可捕获到涉及查询这些系统视图的 PL 对象
SQL> set line 200 pages 9999 long 999999
SQL> col owner for a10
SQL> col name for a30
SQL> col text for a80
SQL> select owner,name,type,text from dba_source where owner not in('SYS', 'SYSTEM', 'SYSMAN', 'OUTLN', 'DIP', 'TSMSYS', 'DBSNMP',
'ORACLE_OCM', 'WMSYS', 'EXFSYS', 'XDB', 'ANONYMOUS', 'ORDSYS',
'ORDPLUGINS', 'SI_INFORMTN_SCHEMA', 'MDSYS', 'MGMT_VIEW', 'PERFSTAT',
'DMSYS', 'CTXSYS', 'OLAPSYS', 'MDDATA', 'APPQOSSYS', 'XS$NULL',
'ORDDATA', 'SPATIAL_WFS_ADMIN_USR', 'SPATIAL_CSW_ADMIN_USR',
'OWBSYS', 'APEX_PUBLIC_USER', 'APEX_030200', 'FLOWS_FILES', 'SCOTT',
'OMS', 'OWBSYS_AUDIT', 'DSG', 'DBMGR', 'PATROL', 'SPA', 'GOLDENGATE',
'DBADM') and owner not like 'MYNET%' and (text like '%USER_TAB_COLUMNS%' or text like '%user_tab_columns%' or text like '%USER%TABLES%' or text like '%user%tables%' or text like '%ALL_TAB_COLUMNS%' or text like '%ALL_tab_columns%' or text like '%ALL%TABLES%' or text like '%ALL%tables%'); 2 3 4 5 6 7 8
OWNER NAME TYPE TEXT
---------- ------------------------------ ------------ --------------------------------------------------------------------------------
U1 PROC_CASE1 PROCEDURE select table_name into v_str from user_tab_columns where table_name='T1';
ZLM PROC_1 PROCEDURE SELECT COUNT(*) INTO V_N FROM USER_TAB_COLUMNS;
ZLM PROC_2 PROCEDURE select count(*) into v_n from user_tab_columns;
afficher l'objet
-- 创建测试视图1
SQL> create view view_1 as select * from user_tables;
View created.
-- 查询 dba_views 获取视图定义
SQL> select owner,view_name,text from dba_views where owner not in('SYS', 'SYSTEM', 'SYSMAN', 'OUTLN', 'DIP', 'TSMSYS', 'DBSNMP',
'ORACLE_OCM', 'WMSYS', 'EXFSYS', 'XDB', 'ANONYMOUS', 'ORDSYS',
'ORDPLUGINS', 'SI_INFORMTN_SCHEMA', 'MDSYS', 'MGMT_VIEW', 'PERFSTAT',
'DMSYS', 'CTXSYS', 'OLAPSYS', 'MDDATA', 'APPQOSSYS', 'XS$NULL',
'ORDDATA', 'SPATIAL_WFS_ADMIN_USR', 'SPATIAL_CSW_ADMIN_USR',
'OWBSYS', 'APEX_PUBLIC_USER', 'APEX_030200', 'FLOWS_FILES', 'SCOTT',
'OMS', 'OWBSYS_AUDIT', 'DSG', 'DBMGR', 'PATROL', 'SPA', 'GOLDENGATE',
'DBADM') and (text like '%USER_TAB_COLUMNS%' or text like '%user_tab_columns%' or text like '%USER%TABLES%' or text like '%user%tables%' or text like '%ALL_TAB_COLUMNS%' or text like '%ALL_tab_columns%' or text like '%ALL%TABLES%' or text like '%ALL%tables%');
2 3 4 5 6 7 8 'DBADM') and (text like '%USER_TAB_COLUMNS%' or text like '%user_tab_columns%' or text like '%USER%TABLES%' or text like '%user%tables%' or text like '%ALL_TAB_COLUMNS%' or text like '%ALL_tab_columns%' or text like '%ALL%TABLES%' or text like '%ALL%tables%')
*
ERROR at line 8:
ORA-00932: inconsistent datatypes: expected NUMBER got LONG
-
dba_source
La colonne de texte dans la vue est de type varchar2 et vous pouvez directement utiliser like pour une requête floue. -
dba_views
La colonne de texte dans la vue est de type long et vous ne pouvez pas utiliser directement like pour effectuer une requête floue, et une erreur ORA-00932 sera signalée.
Solution de contournement : créez d'abord une table, utilisez to_lob
la fonction pour convertir le champ de texte en type clob, puis copiez dba_views dans la table, puis interrogez via le SQL ci-dessus.
-- 创建中间表并将系统视图 dba_views 内容拷贝到该表
SQL> create table my_views as select owner,view_name,to_lob(text) text from dba_views;
Table created.
-- 查询中间表捕获目标视图对象
SQL> select owner,view_name,text from my_views where owner not in('SYS', 'SYSTEM', 'SYSMAN', 'OUTLN', 'DIP', 'TSMSYS', 'DBSNMP', 'ORACLE_OCM', 'WMSYS', 'EXFSYS', 'XDB', 'ANONYMOUS', 'ORDSYS', 'ORDPLUGINS', 'SI_INFORMTN_SCHEMA', 'MDSYS', 'MGMT_VIEW', 'PERFSTAT', 'DMSYS', 'CTXSYS', 'OLAPSYS', 'MDDATA', 'APPQOSSYS', 'XS$NULL', 'ORDDATA', 'SPATIAL_WFS_ADMIN_USR', 'SPATIAL_CSW_ADMIN_USR', 'OWBSYS', 'APEX_PUBLIC_USER', 'APEX_030200', 'FLOWS_FILES', 'SCOTT', 'OMS', 'OWBSYS_AUDIT', 'DSG', 'DBMGR', 'PATROL', 'SPA', 'GOLDENGATE', 'DBADM') and (text like '%USER_TAB_COLUMNS%' or text like '%user_tab_columns%' or text like '%USER%TABLES%' or text like '%user%tables%' or text like '%ALL_TAB_COLUMNS%' or text like '%ALL_tab_columns%' or text like '%ALL%TABLES%' or text like '%ALL%tables%'); 2 3 4 5 6 7 8
OWNER VIEW_NAME TEXT---------- ------------------------------ --------------------------------------------------------------------------------
ZLM VIEW_1 select "TABLE_NAME","TABLESPACE_NAME","CLUSTER_NAME","IOT_NAME","STATUS","PCT_FR EE","PCT_USED","INI_TRANS","MAX_TRANS","INITIAL_EXTENT","NEXT_EXTENT","MIN_EXTEN TS","MAX_EXTENTS","PCT_INCREASE","FREELISTS","FREELIST_GROUPS","LOGGING","BACKED _UP","NUM_ROWS","BLOCKS","EMPTY_BLOCKS","AVG_SPACE","CHAIN_CNT","AVG_ROW_LEN","A VG_SPACE_FREELIST_BLOCKS","NUM_FREELIST_BLOCKS","DEGREE","INSTANCES","CACHE","TA BLE_LOCK","SAMPLE_SIZE","LAST_ANALYZED","PARTITIONED","IOT_TYPE","TEMPORARY","SE CONDARY","NESTED","BUFFER_POOL","ROW_MOVEMENT","GLOBAL_STATS","USER_STATS","DURA TION","SKIP_CORRUPT","MONITORING","CLUSTER_OWNER","DEPENDENCIES","COMPRESSION"," DROPPED" from user_tables
Cette méthode peut répondre aux besoins, mais chaque fois qu'une nouvelle vue est créée, la table doit être supprimée et reconstruite, ce qui est plus fastidieux.
Solution de contournement : créez des vues matérialisées pour remplacer les tables intermédiaires.
-- 创建物化视图
SQL> create materialized view my_mviews
refresh force
on demand
start with sysdate
next sysdate + 10 /(24*60)
as
select owner,view_name,to_lob(text) text from dba_views; 2 3 4 5 6 7
Materialized view created.
-- 创建测试视图2
SQL> CREATE VIEW VIEW_2 AS SELECT * FROM USER_TABLES;
View created.
-- 查看是否捕获到 view_2 视图
SQL> select owner,view_name,text from my_mviews where owner not in('SYS', 'SYSTEM', 'SYSMAN', 'OUTLN', 'DIP', 'TSMSYS', 'DBSNMP',
'ORACLE_OCM', 'WMSYS', 'EXFSYS', 'XDB', 'ANONYMOUS', 'ORDSYS',
'ORDPLUGINS', 'SI_INFORMTN_SCHEMA', 'MDSYS', 'MGMT_VIEW', 'PERFSTAT',
'DMSYS', 'CTXSYS', 'OLAPSYS', 'MDDATA', 'APPQOSSYS', 'XS$NULL',
'ORDDATA', 'SPATIAL_WFS_ADMIN_USR', 'SPATIAL_CSW_ADMIN_USR',
'OWBSYS', 'APEX_PUBLIC_USER', 'APEX_030200', 'FLOWS_FILES', 'SCOTT',
'OMS', 'OWBSYS_AUDIT', 'DSG', 'DBMGR', 'PATROL', 'SPA', 'GOLDENGATE',
'DBADM') and (text like '%USER_TAB_COLUMNS%' or text like '%user_tab_columns%' or text like '%USER%TABLES%' or text like '%user%tables%' or text like '%ALL_TAB_COLUMNS%' or text like '%ALL_tab_columns%' or text like '%ALL%TABLES%' or text like '%ALL%tables%'); 2 3 4 5 6 7 8
OWNER VIEW_NAME TEXT
---------- ------------------------------ --------------------------------------------------------------------------------
ZLM VIEW_1 select "TABLE_NAME","TABLESPACE_NAME","CLUSTER_NAME","IOT_NAME","STATUS","PCT_FR
EE","PCT_USED","INI_TRANS","MAX_TRANS","INITIAL_EXTENT","NEXT_EXTENT","MIN_EXTEN
TS","MAX_EXTENTS","PCT_INCREASE","FREELISTS","FREELIST_GROUPS","LOGGING","BACKED
_UP","NUM_ROWS","BLOCKS","EMPTY_BLOCKS","AVG_SPACE","CHAIN_CNT","AVG_ROW_LEN","A
VG_SPACE_FREELIST_BLOCKS","NUM_FREELIST_BLOCKS","DEGREE","INSTANCES","CACHE","TA
BLE_LOCK","SAMPLE_SIZE","LAST_ANALYZED","PARTITIONED","IOT_TYPE","TEMPORARY","SE
CONDARY","NESTED","BUFFER_POOL","ROW_MOVEMENT","GLOBAL_STATS","USER_STATS","DURA
TION","SKIP_CORRUPT","MONITORING","CLUSTER_OWNER","DEPENDENCIES","COMPRESSION","
DROPPED" from user_tables
-- 查看物化视图刷新时间
SQL> select owner,mview_name,last_refresh_type,last_refresh_date from user_mviews;
OWNER MVIEW_NAME LAST_REF LAST_REFRESH_DATE
---------- ------------------------------ -------- -------------------
ZLM MY_MVIEWS COMPLETE 2023-08-03 16:07:15
-- 手动刷新物化视图
SQL> exec dbms_mview.refresh('my_mviews');
PL/SQL procedure successfully completed.
SQL> select owner,mview_name,last_refresh_type,last_refresh_date from user_mviews;
OWNER MVIEW_NAME LAST_REF LAST_REFRESH_DATE
---------- ------------------------------ -------- -------------------
ZLM MY_MVIEWS COMPLETE 2023-08-03 16:21:45
-- 再次查询物化视图,此时 view_2 也能被捕获到了,这样就无需重复建表,当有新视图被创建的时候,只需手动刷新物化视图即可
SQL> select owner,view_name,text from my_mviews where owner not in('SYS', 'SYSTEM', 'SYSMAN', 'OUTLN', 'DIP', 'TSMSYS', 'DBSNMP',
'ORACLE_OCM', 'WMSYS', 'EXFSYS', 'XDB', 'ANONYMOUS', 'ORDSYS',
'ORDPLUGINS', 'SI_INFORMTN_SCHEMA', 'MDSYS', 'MGMT_VIEW', 'PERFSTAT',
'DMSYS', 'CTXSYS', 'OLAPSYS', 'MDDATA', 'APPQOSSYS', 'XS$NULL',
'ORDDATA', 'SPATIAL_WFS_ADMIN_USR', 'SPATIAL_CSW_ADMIN_USR',
'OWBSYS', 'APEX_PUBLIC_USER', 'APEX_030200', 'FLOWS_FILES', 'SCOTT',
'OMS', 'OWBSYS_AUDIT', 'DSG', 'DBMGR', 'PATROL', 'SPA', 'GOLDENGATE',
'DBADM') and (text like '%USER_TAB_COLUMNS%' or text like '%user_tab_columns%' or text like '%USER%TABLES%' or text like '%user%tables%' or text like '%ALL_TAB_COLUMNS%' or text like '%ALL_tab_columns%' or text like '%ALL%TABLES%' or text like '%ALL%tables%'); 2 3 4 5 6 7 8
OWNER VIEW_NAME TEXT
---------- ------------------------------ --------------------------------------------------------------------------------
ZLM VIEW_1 select "TABLE_NAME","TABLESPACE_NAME","CLUSTER_NAME","IOT_NAME","STATUS","PCT_FR
EE","PCT_USED","INI_TRANS","MAX_TRANS","INITIAL_EXTENT","NEXT_EXTENT","MIN_EXTEN
TS","MAX_EXTENTS","PCT_INCREASE","FREELISTS","FREELIST_GROUPS","LOGGING","BACKED
_UP","NUM_ROWS","BLOCKS","EMPTY_BLOCKS","AVG_SPACE","CHAIN_CNT","AVG_ROW_LEN","A
VG_SPACE_FREELIST_BLOCKS","NUM_FREELIST_BLOCKS","DEGREE","INSTANCES","CACHE","TA
BLE_LOCK","SAMPLE_SIZE","LAST_ANALYZED","PARTITIONED","IOT_TYPE","TEMPORARY","SE
CONDARY","NESTED","BUFFER_POOL","ROW_MOVEMENT","GLOBAL_STATS","USER_STATS","DURA
TION","SKIP_CORRUPT","MONITORING","CLUSTER_OWNER","DEPENDENCIES","COMPRESSION","
DROPPED" from user_tables
ZLM VIEW_2 select "TABLE_NAME","TABLESPACE_NAME","CLUSTER_NAME","IOT_NAME","STATUS","PCT_FR
EE","PCT_USED","INI_TRANS","MAX_TRANS","INITIAL_EXTENT","NEXT_EXTENT","MIN_EXTEN
TS","MAX_EXTENTS","PCT_INCREASE","FREELISTS","FREELIST_GROUPS","LOGGING","BACKED
_UP","NUM_ROWS","BLOCKS","EMPTY_BLOCKS","AVG_SPACE","CHAIN_CNT","AVG_ROW_LEN","A
VG_SPACE_FREELIST_BLOCKS","NUM_FREELIST_BLOCKS","DEGREE","INSTANCES","CACHE","TA
BLE_LOCK","SAMPLE_SIZE","LAST_ANALYZED","PARTITIONED","IOT_TYPE","TEMPORARY","SE
CONDARY","NESTED","BUFFER_POOL","ROW_MOVEMENT","GLOBAL_STATS","USER_STATS","DURA
TION","SKIP_CORRUPT","MONITORING","CLUSTER_OWNER","DEPENDENCIES","COMPRESSION","
DROPPED" from USER_TABLES
solution
user_tab_columns
Bien que le remplacement de la vue dans la procédure stockée all_tab_columns
puisse être utilisé comme solution temporaire, il présente les inconvénients suivants :
- Le code métier doit être modifié, c'est-à-dire que la partie de la procédure stockée qui interroge les vues système pertinentes doit être remplacée.
- Les utilisateurs qui utilisent des synonymes pour accéder aux objets doivent disposer de l'autorisation système SELECT ANY TABLE, sinon l'
all_
objet cible ne pourra pas être interrogé même si la vue est utilisée. - Accordez à l'utilisateur d'exécution l'autorité dba, modifiez la requête SQL d'origine et ajoutez la condition Owner='XXX' (il existe des risques de sécurité et ne sont pas recommandés).
- OB peut fournir un correctif pour résoudre complètement ce problème.
conclusion du problème
Dans OB, USER_TAB_COLUMNS
la logique selon laquelle les utilisateurs ordinaires interrogent les autorisations d'affichage du système n'est pas cohérente avec Oracle, ce qui entraîne des différences dans les résultats des requêtes.
En plus des USER_TAB_COLUMNS
vues, il existe d'autres USER_
vues commençant par celles qui présentent également des problèmes similaires, telles que : USER_SYNONYMS
, USER_TABLES
etc.
Pour les objets existants dans le système, vous devez vérifier dès que possible et confirmer quels objets utilisent ces vues système. Avant que le problème ne soit complètement résolu, il est recommandé d'apporter des modifications temporaires au code concerné afin qu'il puisse continuer à compléter les fonctionnalités ultérieures. vérification.
Pour des articles plus techniques, veuillez visiter : https://opensource.actionsky.com/
À propos de SQLE
SQLE de la communauté open source Axon est un outil d'audit SQL destiné aux utilisateurs et gestionnaires de bases de données qui prend en charge les audits multi-scénarios, les processus en ligne standardisés, la prise en charge native des audits MySQL et les types de bases de données évolutives.
SQLE obtenir
taper | adresse |
---|---|
Dépôt | https://github.com/actiontech/sqle |
document | https://actiontech.github.io/sqle-docs/ |
publier des nouvelles | https://github.com/actiontech/sqle/releases |
Documentation de développement du plug-in d'audit des données | https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse |