Cuando se llaman los procedimientos almacenados bajo los inquilinos de Oracle y OB Oracle, el rendimiento de los dos es inconsistente, lo que resulta en un empalme incompleto del texto SQL obtenido, lo que afecta las pruebas funcionales en el lado comercial. Este artículo realizará pruebas y verificaciones relevantes sobre este tema.
Autor: Zhao Liming, miembro del equipo MySQL DBA de Aikesheng. Está familiarizado con bases de datos como Oracle y MySQL. Es bueno para diagnosticar problemas de rendimiento de bases de datos y analizar problemas de transacciones y bloqueos. Es responsable de manejar la operación diaria y mantenimiento del MySQL del cliente y la plataforma DMP de desarrollo propio de nuestra empresa Pregunta: Estoy muy interesado en las tecnologías relacionadas con bases de datos de código abierto.
Producido por la comunidad de código abierto de Aikeson, el contenido original no se puede utilizar sin autorización. Comuníquese con el editor e indique la fuente para la reimpresión.
Este artículo tiene aproximadamente 3100 palabras y se espera que su lectura demore 10 minutos.
fondo
Recientemente, un cliente encontró una falla: cuando se llamaron los procedimientos almacenados bajo los inquilinos de Oracle y OB Oracle, el rendimiento de los dos fue inconsistente, lo que resultó en un empalme incompleto del texto SQL obtenido, lo que afectó las pruebas funcionales en el lado comercial.
La lógica del procedimiento almacenado del cliente no es complicada: simplemente consulta la vista del sistema user_tab_columns
para obtener el nombre de la tabla del usuario y luego realiza un empalme SQL para completar la lógica empresarial posterior.
Este artículo realizará pruebas y verificaciones relevantes sobre este tema.
Recurrencia del problema
Validación en entorno 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>
Se puede ver que en Oracle, ya sea el usuario u1 o u2, el nombre de la tabla se puede devolver correctamente al llamar al procedimiento almacenado, lo que indica que los resultados devueltos user_tab_columns
por las dos vistas de consulta son consistentes, lo que también está en línea con las expectativas.
Validación en entorno 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)
De hecho, se pueden encontrar algunas pistas aquí: aunque los usuarios pueden cambiarse a través de conn en OB, y los usuarios cambiados también pueden acceder a sus propios objetos, al acceder a vistas como USER_, los resultados devueltos son diferentes a los de Oracle.
Cuando el usuario u1 consulta user_tab_columns
la tabla, solo puede ver las tablas bajo el usuario SYS (la tabla C fue creada por el usuario SYS), por lo que el procedimiento almacenado no puede devolver el nombre de la tabla T1 y el resultado de la consulta está vacío.
-- 直连 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)
Cuando el usuario u2 no tiene el permiso del sistema SELECCIONAR CUALQUIER TABLA, incluso si all_tab_columns
se consulta la vista, no se puede obtener información sobre las tablas creadas por otros usuarios.
Solucionar problemas de objetos relacionados que llaman a vistas del sistema
Objeto PL
Objetos PL, como funciones, procedimientos almacenados, 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;
ver objeto
-- 创建测试视图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 columna de texto en la vista es de tipo varchar2 y puede usarla directamente para consultas difusas. -
dba_views
La columna de texto en la vista es de tipo largo y no puede usar like directamente para realizar consultas difusas, y se informará un error ORA-00932.
Solución alternativa: primero cree una tabla, use to_lob
la función para convertir el campo de texto al tipo clob, luego copie dba_views a la tabla y luego consulte a través del SQL anterior.
-- 创建中间表并将系统视图 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
Este método puede satisfacer las necesidades, pero cada vez que se crea una nueva vista, es necesario eliminar y reconstruir la tabla, lo cual es más engorroso.
Solución alternativa: cree vistas materializadas para reemplazar las tablas intermedias.
-- 创建物化视图
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
solución
user_tab_columns
Aunque reemplazar la vista en el procedimiento almacenado all_tab_columns
puede usarse como solución temporal, tiene las siguientes desventajas:
- Es necesario modificar el código comercial, es decir, es necesario reemplazar la parte del procedimiento almacenado que consulta las vistas relevantes del sistema.
- Los usuarios que utilizan sinónimos para acceder a objetos deben tener el permiso del sistema SELECCIONAR CUALQUIER TABLA. De lo contrario, el
all_
objeto de destino no se puede consultar incluso si se utiliza la vista. - Otorgue al usuario de ejecución autoridad dba, modifique la consulta SQL original y agregue la condición propietario = 'XXX' (existen riesgos de seguridad y no se recomienda).
- OB puede proporcionar un parche para resolver completamente este problema.
conclusión del asunto
En OB, USER_TAB_COLUMNS
la lógica de los usuarios normales que consultan los permisos de vista del sistema no es coherente con la de Oracle, lo que genera diferencias en los resultados de la consulta.
Además de USER_TAB_COLUMNS
las vistas, hay otras USER_
vistas que comienzan con las que también tienen problemas similares, como por ejemplo: USER_SYNONYMS
, USER_TABLES
etc.
Para los objetos existentes en el sistema, debe verificar lo antes posible y confirmar qué objetos usan estas vistas del sistema. Antes de que el problema se solucione por completo, se recomienda realizar modificaciones temporales en el código relevante para que pueda continuar completando funciones posteriores. verificación.
Para obtener más artículos técnicos, visite: https://opensource.actionsky.com/
Acerca de SQLE
SQLE de la comunidad de código abierto Axon es una herramienta de auditoría SQL para usuarios y administradores de bases de datos que admite auditorías de múltiples escenarios, procesos en línea estandarizados, soporte nativo para auditorías MySQL y tipos de bases de datos escalables.
obtener SQLE
tipo | DIRECCIÓN |
---|---|
Repositorio | https://github.com/actiontech/sqle |
documento | https://actiontech.github.io/sqle-docs/ |
noticias de lanzamiento | https://github.com/actiontech/sqle/releases |
Documentación de desarrollo del complemento de auditoría de datos | https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse |