执行函数嵌入 SELECT sql 查询以提高性能
Executing function embedded SELECT sql query to increase performance
我有以下 SQL 查询,它将 return 特定 table 中的列的名称。假设它 return 'USER_PK' 作为列名,当它 运行s.
查询:
SELECT max(COLUMN_NAME)
FROM ALL_TAB_COLUMNS
WHERE OWNER= 'DW_01'
AND table_name='D_O_USERS'
AND COLUMN_NAME<>'USER_PK';
现在我想 运行 上述查询作为函数的一部分,而不是 运行 将其 return 存储在变量中(使用 INTO
或 initial_sql 之类的属性:= '...',后跟 exec )我需要将它 运行 放在一行代码中,如下所示(请参阅粗体部分).. . 到目前为止,我一直没有成功,因为它在使用引号时被解释为字符串 ...
CREATE OR REPLACE function DW_01.EXECUTE_AUTO (db_schema IN VARCHAR2, db_table IN VARCHAR2, pk_name IN VARCHAR2, id_pk IN INTEGER) RETURN VARCHAR2
IS
result VARCHAR2(4000);
begin
EXECUTE IMMEDIATE 'select STANDARD_HASH( '|| **SELECT max( COLUMN_NAME) FROM ALL_TAB_COLUMNS WHERE OWNER='' || db_schema || '' AND table_name=''||db_table ||'' AND COLUMN_NAME<>'' ||pk_name ||'** ,''SHA512'' ) from '||db_table||' where '|| pk_name ||'='||id_pk into RESULT ;
return result;
end;
非常感谢您的想法!
您需要像下面这样修改您的代码 -
CREATE OR REPLACE function DW_01.EXECUTE_AUTO (db_schema IN VARCHAR2,
db_table IN VARCHAR2,
pk_name IN VARCHAR2,
id_pk IN INTEGER) RETURN VARCHAR2
IS
result VARCHAR2(4000);
begin
EXECUTE IMMEDIATE 'select STANDARD_HASH( ' || pk_name || ',256 )
from '||db_table||' where '|| pk_name ||'='||id_pk into RESULT;
return result;
end;
/
在 SQL 中 运行 动态 SQL 只有几种方法,它们既不漂亮也不快速。下面的函数使用 DBMS_XMLGEN.GETXML 动态地 运行 一个 SQL 语句。
create or replace function execute_auto(db_schema in varchar2, db_table in varchar2, pk_name in varchar2, id_pk in integer) return varchar2
is
v_column_name varchar2(128);
v_result varchar2(4000);
begin
select standard_hash(to_number(extractValue(xml_results, '/ROWSET/ROW/' || max_column)), 'SHA512') hash_value
into v_result
from
(
--Create a single XML file with the ROWIDs that match the condition.
select max(column_name) max_column, xmltype(dbms_xmlgen.getxml
('
select '||max(column_name)||'
from '||db_schema||'.'||db_table||'
where id = '||id_pk
)) xml_results
from all_tab_columns
where owner = db_schema
and table_name = db_table
and column_name <> pk_name
);
return v_result;
end;
/
例如,让我们创建这个包含 100,000 行的示例 table:
--drop table test1;
create table test1(id number, a number, b number, constraint pk_test1 primary key(id));
insert into test1
select level, level, level from dual connect by level <= 100000;
commit;
这显示了如何使用该功能;
select execute_auto(user, 'TEST1', 'ID', id) hash
from test1 where id = 1;
HASH
----
A36753F534728ED84A463ECB13750B8E920A7E4D90244258DE77D9800A0F3DAF8CBAD49602E960A2355933C689A23C30377CE10FC4B8E1F197739FF86C791022
除了类型转换和SQL注入的问题外,性能也很糟糕。在我的机器上以这种方式选择所有 100,000 行需要 200 秒。
select sum(length(execute_auto(user, 'TEST1', 'ID', id))) from test1;
通常,运行将所有内容都集中在一个 SELECT 语句中是提高性能的好方法。但这种极端类型的动态 SQL 永远不会 运行 快。您可能想重新考虑您的方法。不要尝试在一次 运行 一行的函数中优化 SQL,而是尝试将流程更改为每 table[=14 处理一次=]
我有以下 SQL 查询,它将 return 特定 table 中的列的名称。假设它 return 'USER_PK' 作为列名,当它 运行s.
查询:
SELECT max(COLUMN_NAME)
FROM ALL_TAB_COLUMNS
WHERE OWNER= 'DW_01'
AND table_name='D_O_USERS'
AND COLUMN_NAME<>'USER_PK';
现在我想 运行 上述查询作为函数的一部分,而不是 运行 将其 return 存储在变量中(使用 INTO
或 initial_sql 之类的属性:= '...',后跟 exec )我需要将它 运行 放在一行代码中,如下所示(请参阅粗体部分).. . 到目前为止,我一直没有成功,因为它在使用引号时被解释为字符串 ...
CREATE OR REPLACE function DW_01.EXECUTE_AUTO (db_schema IN VARCHAR2, db_table IN VARCHAR2, pk_name IN VARCHAR2, id_pk IN INTEGER) RETURN VARCHAR2
IS
result VARCHAR2(4000);
begin
EXECUTE IMMEDIATE 'select STANDARD_HASH( '|| **SELECT max( COLUMN_NAME) FROM ALL_TAB_COLUMNS WHERE OWNER='' || db_schema || '' AND table_name=''||db_table ||'' AND COLUMN_NAME<>'' ||pk_name ||'** ,''SHA512'' ) from '||db_table||' where '|| pk_name ||'='||id_pk into RESULT ;
return result;
end;
非常感谢您的想法!
您需要像下面这样修改您的代码 -
CREATE OR REPLACE function DW_01.EXECUTE_AUTO (db_schema IN VARCHAR2,
db_table IN VARCHAR2,
pk_name IN VARCHAR2,
id_pk IN INTEGER) RETURN VARCHAR2
IS
result VARCHAR2(4000);
begin
EXECUTE IMMEDIATE 'select STANDARD_HASH( ' || pk_name || ',256 )
from '||db_table||' where '|| pk_name ||'='||id_pk into RESULT;
return result;
end;
/
在 SQL 中 运行 动态 SQL 只有几种方法,它们既不漂亮也不快速。下面的函数使用 DBMS_XMLGEN.GETXML 动态地 运行 一个 SQL 语句。
create or replace function execute_auto(db_schema in varchar2, db_table in varchar2, pk_name in varchar2, id_pk in integer) return varchar2
is
v_column_name varchar2(128);
v_result varchar2(4000);
begin
select standard_hash(to_number(extractValue(xml_results, '/ROWSET/ROW/' || max_column)), 'SHA512') hash_value
into v_result
from
(
--Create a single XML file with the ROWIDs that match the condition.
select max(column_name) max_column, xmltype(dbms_xmlgen.getxml
('
select '||max(column_name)||'
from '||db_schema||'.'||db_table||'
where id = '||id_pk
)) xml_results
from all_tab_columns
where owner = db_schema
and table_name = db_table
and column_name <> pk_name
);
return v_result;
end;
/
例如,让我们创建这个包含 100,000 行的示例 table:
--drop table test1;
create table test1(id number, a number, b number, constraint pk_test1 primary key(id));
insert into test1
select level, level, level from dual connect by level <= 100000;
commit;
这显示了如何使用该功能;
select execute_auto(user, 'TEST1', 'ID', id) hash
from test1 where id = 1;
HASH
----
A36753F534728ED84A463ECB13750B8E920A7E4D90244258DE77D9800A0F3DAF8CBAD49602E960A2355933C689A23C30377CE10FC4B8E1F197739FF86C791022
除了类型转换和SQL注入的问题外,性能也很糟糕。在我的机器上以这种方式选择所有 100,000 行需要 200 秒。
select sum(length(execute_auto(user, 'TEST1', 'ID', id))) from test1;
通常,运行将所有内容都集中在一个 SELECT 语句中是提高性能的好方法。但这种极端类型的动态 SQL 永远不会 运行 快。您可能想重新考虑您的方法。不要尝试在一次 运行 一行的函数中优化 SQL,而是尝试将流程更改为每 table[=14 处理一次=]