私はいくつかのチューニングを行っていましたが、私のExplain Plansから驚くべき結果が得られました。 "Pure SQL Query"とSQLとの間の説明計画を関数と比較していました。 私は、PL/SQLで行うよりもSQLで実行するほうが速いという一般的な考えに基づいているため、純粋なSQLクエリ と比較して、コストとアクセスパスの点で後者が優れていることに驚きました。SQLでのファンクションのパフォーマンス
サンプルDDL以下DML(PSちょうどこのサンプルのためのダミーデータとダミーオブジェクトを作成しました。):ここで
Create Table EMP_DATA_TL
(
emp_id number
, emp_name varchar2(100)
, organization_id number
, location_id number
, Start_date date
, end_date date
);
create table organization_TL
(
organization_id number
, ORGANIZATION_NAME VARCHAR2(100)
, Start_date date
, end_date date
);
create table location_TL
(
location_id number
, location_name varchar2(100)
, Start_date date
, end_date date
);
insert into EMP_DATA_TL (emp_id, emp_name, organization_id, location_id, Start_date, end_date) values (1, 'TEST 1', 1, 2, SYSDATE, NULL);
insert into EMP_DATA_TL (emp_id, emp_name, organization_id, location_id, Start_date, end_date) values (2, 'TEST 2', 1, 3, SYSDATE, NULL);
insert into EMP_DATA_TL (emp_id, emp_name, organization_id, location_id, Start_date, end_date) values (3, 'TEST 3', 3, 1, SYSDATE, NULL);
insert into organization_TL (organization_id, ORGANIZATION_NAME, Start_date, end_date) values (1, 'ORG 1', SYSDATE, NULL);
insert into organization_TL (organization_id, ORGANIZATION_NAME, Start_date, end_date) values (2, 'ORG 2', SYSDATE, NULL);
insert into organization_TL (organization_id, ORGANIZATION_NAME, Start_date, end_date) values (3, 'ORG 3', SYSDATE, NULL);
insert into location_TL (location_id, location_name, Start_date, end_date) values (1, 'LOC 1', SYSDATE, NULL);
insert into location_TL (location_id, location_name, Start_date, end_date) values (2, 'LOC 2', SYSDATE, NULL);
insert into location_TL (location_id, location_name, Start_date, end_date) values (3, 'LOC 3', SYSDATE, NULL);
COMMIT;
がパッケージです:
CREATE OR REPLACE PACKAGE GET_DATA_TST
AS
FUNCTION GET_ORG (p_organization_id NUMBER) RETURN VARCHAR2;
FUNCTION GET_LOC (P_LOCATION_ID NUMBER) RETURN VARCHAR2;
END GET_DATA_TST;
CREATE OR REPLACE PACKAGE BODY GET_DATA_TST
AS
FUNCTION GET_ORG (p_organization_id NUMBER) RETURN VARCHAR2
AS
L_ORG_NAME location_TL.location_name%TYPE;
BEGIN
SELECT ORGANIZATION_NAME
INTO L_ORG_NAME
FROM organization_TL
WHERE organization_id = p_organization_id;
return L_ORG_NAME;
exception
when no_data_found then
return null;
END GET_ORG;
FUNCTION GET_LOC (P_LOCATION_ID NUMBER) RETURN VARCHAR2
AS
L_LOC_NAME location_TL.location_name%TYPE;
BEGIN
SELECT LOCATION_NAME
INTO L_LOC_NAME
FROM location_TL
WHERE location_id = P_LOCATION_ID;
return L_LOC_NAME;
exception
when no_data_found then
return null;
END GET_LOC;
END GET_DATA_TST;
は、精度については、表の統計を収集します。
EXEC dbms_stats.gather_table_stats('APPS', 'EMP_DATA_TL');
EXEC dbms_stats.gather_table_stats('APPS', 'organization_TL');
EXEC dbms_stats.gather_table_stats('APPS', 'location_TL');
クエリ1:純粋なSQL
SELECT EMP.EMP_NAME
, ORG.ORGANIZATION_NAME
, LOC.LOCATION_NAME
FROM EMP_DATA_TL EMP
, organization_TL ORG
, location_TL LOC
WHERE EMP.ORGANIZATION_ID = ORG.ORGANIZATION_ID
AND LOC.LOCATION_ID = EMP.LOCATION_ID
AND EMP.EMP_NAME = 'TEST 3';
クエリ1件の結果:
Plan hash value: 1708296422
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 31 | 15 (0)| 00:00:01 |
|* 1 | HASH JOIN | | 1 | 31 | 15 (0)| 00:00:01 |
|* 2 | HASH JOIN | | 1 | 22 | 10 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| EMP_DATA_TL | 1 | 13 | 5 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL| ORGANIZATION_TL | 3 | 27 | 5 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL | LOCATION_TL | 3 | 27 | 5 (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("LOC"."LOCATION_ID"="EMP"."LOCATION_ID")
2 - access("EMP"."ORGANIZATION_ID"="ORG"."ORGANIZATION_ID")
3 - filter("EMP"."EMP_NAME"='TEST 3')
クエリ2:クエリとして2つの結果(同じ機能を持つSQL
SELECT EMP.EMP_NAME
, GET_DATA_TST.GET_ORG(ORGANIZATION_ID) ORGANIZATION_NAME
, GET_DATA_TST.GET_LOC(LOCATION_ID) LOCATION_NAME
FROM EMP_DATA_TL EMP
WHERE EMP.EMP_NAME = 'TEST 3';
クエリ
EMP_NAME ORGANIZATION_NAME LOCATION_NAME
-------- ----------------- -------------
TEST 3 ORG 3 LOC 1
は、クエリ1の計画を説明1結果):
EMP_NAME ORGANIZATION_NAME LOCATION_NAME
-------- ----------------- -------------
TEST 3 ORG 3 LOC 1
クエリ2は、計画を説明:
Plan hash value: 765802585
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 5 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| EMP_DATA_TL | 1 | 13 | 5 (0)| 00:00:01 |
---------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("EMP"."EMP_NAME"='TEST 3')
ドロップ文ちょうどあなたが「日を必要とする場合には:
DROP TABLE EMP_DATA_TL;
DROP table organization_TL;
DROP table location_TL;
質問:
- このような場合は理由を任意のアイデア?または任意の説明?
- これらのタイプのクエリには常に関数を使用することをお勧めしますか?
- お持ちの情報やヒントを教えてください。
ありがとうございました!
関数内で実行されるSQLは、Explainプランには含まれません。しかし、それはあなたに何かコストがかからなかったということではありません。それはちょうどあなたに示されていませんでした。 – sstan
私はそれについても考えました。関数で実行されたSQLの結果を知る方法はありますか?結果にそれを含める?ありがとう! @sstan –
dbms_profilerを使用してpl/sqlをプロファイルすることができます – OldProgrammer