2016-11-08 4 views
2

私はいくつかのチューニングを行っていましたが、私の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; 

質問:

  1. このような場合は理由を任意のアイデア?または任意の説明?
  2. これらのタイプのクエリには常に関数を使用することをお勧めしますか?
  3. お持ちの情報やヒントを教えてください。

ありがとうございました!

+6

関数内で実行されるSQLは、Explainプランには含まれません。しかし、それはあなたに何かコストがかからなかったということではありません。それはちょうどあなたに示されていませんでした。 – sstan

+0

私はそれについても考えました。関数で実行されたSQLの結果を知る方法はありますか?結果にそれを含める?ありがとう! @sstan –

+2

dbms_profilerを使用してpl/sqlをプロファイルすることができます – OldProgrammer

答えて

2
  1. どれ同上なぜこれが当てはまるのでしょうか?または任意の説明?あなたのテストケースは、Stackoverflowのサンプルコードの99%を上回っていますが、まだ重要な項目がいくつか欠落しています。
  2. これらの種類のクエリには常に関数を使用することをお勧めしますか?いいえ。ほとんどの場合、関数を避けて純粋なSQLを使用する方が良いです。
  3. お持ちの情報やヒントを教えてください。詳細は以下を参照してください。何が不足しているか

- 再帰SQL

言及sstanとして、PL/SQLコードによって生成された再帰的SQL文をカバーしていない説明のプラン。あなたはこれらのようなものを再帰的SQL文を見つけることができます

select sql_id, sql_fulltext from gv$sql where lower(sql_fulltext) like 'select organization_name from organization_tl where organization_id = :b1 '; 
select sql_id, sql_fulltext from gv$sql where lower(sql_fulltext) like 'select location_name from location_tl where location_id%'; 

は、これらのようなSQL文を使用して計画を見る:

select * from table(dbms_xplan.display_cursor('f25v7jzaru38w')); 
select * from table(dbms_xplan.display_cursor('8akhcs16wn8fd')); 

一人一人が自分のマシン上の3のコストを持っています。あなたは5の本来のコストにそれらの両方を追加した場合、あなたは何が不足しているか11.

を合わせた費用を取得 - リアルなデータとデータ構造は

15と11のコストを比較するために無意味ことができますいくつかの理由があります。

テーブルが非常に小さい場合、それらにアクセスするアルゴリズムはほとんど問題ではありません。おそらく、わずか数行のテーブルは、単一の8KBブロック内に収まる可能性があります。この場合、索引にはさらに8KBのブロックが必要となるため、完全な表スキャンが索引読取りより常に優れています。

これはどのくらいの時間差がありますか? 1マイクロ秒?従業員テーブルをクエリする予定がない限り、10億回の違いは問題ではありません。

テーブルが大きくなると、インデックスの不足が重要になります。その場合、各関数呼び出しで実行されるこれらのフル・テーブル・スキャンは悲惨です。 1つのクエリは大したものではありませんが、少なくとも1回は各テーブルから読み取る必要があります。

パフォーマンスの見積りでは、パフォーマンスの見積もりを見ているときは常に心に留めておくべき

2つのこと苦手なもの:プログラムが(一般的に)終了しますかどうかを判断することは不可能である

  1. 、どのくらいの時間かかります。これはhalting problemとして知られています。
  2. Oracleオプティマイザは、パフォーマンスを予測するために多くのトリックを使用します。しかし、予測は常に間違っています。

これは、11と15の差がちょうどノイズであることを意味します。 「コストベースオプティマイザ」と呼ばれていますが、実際のコストはそれほど重要ではありません。実行計画に表示されるアルゴリズムとデータ構造についてもっと心配してください。彼らが一桁以上離れていなければ、コストや基数の数字を心配しないでください。

現実的なデータ、現実的なデータ構造、現実的な環境で常にテストする必要があります。

+0

偉大な答えジョンのおかげで!私はあなたの答えから確かに学んだ。ありがとう! –

-2

は、関数内のルーチンのためのクエリプランを取得するために

EXPLAIN EXTENDED 

で試してみてください。

+0

それはどういう意味ですか? @DuduMarkovitz –

+0

MySQLの構文は、Oracleに関連していません –

+0

ああ、はい、私はExplain Extendedのクイック検索を行い、それがMySQL用であることを発見しました。ありがとう。 –

0

機能パフォーマンスPOC

(Oracle Database 11g Express Editionリリース11.2.0.2。0 - 64ビットの製造)

create or replace function f return number is begin return 1; end; 
/

create table t as 
with t (n) as (select 1 from dual union all select n+1 from t where n < 100) 
select 1 as n from t t0,t t1,t t2,t t3 
; 

select count(1) from t; 

2.5

select count(f()) from t; 

関連する問題