PIPELINED 테이블 함수를 사용하여 다른 접근 방식을 제안하고 싶습니다. 문자열을 분할하기 위해 고유 한 사용자 정의 함수를 제공한다는 점을 제외하면 XMLTABLE의 기술과 다소 유사합니다.
-- Create a collection type to hold the results
CREATE OR REPLACE TYPE typ_str2tbl_nst AS TABLE OF VARCHAR2(30);
/
-- Split the string according to the specified delimiter
CREATE OR REPLACE FUNCTION str2tbl (
p_string VARCHAR2,
p_delimiter CHAR DEFAULT ','
)
RETURN typ_str2tbl_nst PIPELINED
AS
l_tmp VARCHAR2(32000) := p_string || p_delimiter;
l_pos NUMBER;
BEGIN
LOOP
l_pos := INSTR( l_tmp, p_delimiter );
EXIT WHEN NVL( l_pos, 0 ) = 0;
PIPE ROW ( RTRIM( LTRIM( SUBSTR( l_tmp, 1, l_pos-1) ) ) );
l_tmp := SUBSTR( l_tmp, l_pos+1 );
END LOOP;
END str2tbl;
/
-- The problem solution
SELECT name,
project,
TRIM(COLUMN_VALUE) error
FROM t, TABLE(str2tbl(error));
결과 :
NAME PROJECT ERROR
---------- ---------- --------------------
108 test Err1
108 test Err2
108 test Err3
109 test2 Err1
이러한 유형의 접근 방식의 문제점은 종종 옵티마이 저가 테이블 함수의 카디널리티를 알지 못하고 추측을해야한다는 것입니다. 이는 실행 계획에 잠재적으로 해로울 수 있으므로 최적화 프로그램에 대한 실행 통계를 제공하도록이 솔루션을 확장 할 수 있습니다.
위 쿼리에서 EXPLAIN PLAN을 실행하여이 최적화 프로그램 추정치를 볼 수 있습니다.
Execution Plan
----------------------------------------------------------
Plan hash value: 2402555806
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 16336 | 366K| 59 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 16336 | 366K| 59 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL | T | 2 | 42 | 3 (0)| 00:00:01 |
| 3 | COLLECTION ITERATOR PICKLER FETCH| STR2TBL | 8168 | 16336 | 28 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
콜렉션에 3 개의 값만 있지만 옵티마이 저는 이에 대해 8168 개의 행을 추정했습니다 (기본값). 이것은 처음에는 무관 해 보일 수 있지만 최적화 프로그램이 차선책을 결정하는 것으로 충분할 수 있습니다.
솔루션은 옵티 마이저 확장을 사용하여 콜렉션에 대한 통계를 제공하는 것입니다.
-- Create the optimizer interface to the str2tbl function
CREATE OR REPLACE TYPE typ_str2tbl_stats AS OBJECT (
dummy NUMBER,
STATIC FUNCTION ODCIGetInterfaces ( p_interfaces OUT SYS.ODCIObjectList )
RETURN NUMBER,
STATIC FUNCTION ODCIStatsTableFunction ( p_function IN SYS.ODCIFuncInfo,
p_stats OUT SYS.ODCITabFuncStats,
p_args IN SYS.ODCIArgDescList,
p_string IN VARCHAR2,
p_delimiter IN CHAR DEFAULT ',' )
RETURN NUMBER
);
/
-- Optimizer interface implementation
CREATE OR REPLACE TYPE BODY typ_str2tbl_stats
AS
STATIC FUNCTION ODCIGetInterfaces ( p_interfaces OUT SYS.ODCIObjectList )
RETURN NUMBER
AS
BEGIN
p_interfaces := SYS.ODCIObjectList ( SYS.ODCIObject ('SYS', 'ODCISTATS2') );
RETURN ODCIConst.SUCCESS;
END ODCIGetInterfaces;
-- This function is responsible for returning the cardinality estimate
STATIC FUNCTION ODCIStatsTableFunction ( p_function IN SYS.ODCIFuncInfo,
p_stats OUT SYS.ODCITabFuncStats,
p_args IN SYS.ODCIArgDescList,
p_string IN VARCHAR2,
p_delimiter IN CHAR DEFAULT ',' )
RETURN NUMBER
AS
BEGIN
-- I'm using basically half the string lenght as an estimator for its cardinality
p_stats := SYS.ODCITabFuncStats( CEIL( LENGTH( p_string ) / 2 ) );
RETURN ODCIConst.SUCCESS;
END ODCIStatsTableFunction;
END;
/
-- Associate our optimizer extension with the PIPELINED function
ASSOCIATE STATISTICS WITH FUNCTIONS str2tbl USING typ_str2tbl_stats;
결과 실행 계획 테스트 :
Execution Plan
----------------------------------------------------------
Plan hash value: 2402555806
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 23 | 59 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 23 | 59 (0)| 00:00:01 |
| 2 | TABLE ACCESS FULL | T | 2 | 42 | 3 (0)| 00:00:01 |
| 3 | COLLECTION ITERATOR PICKLER FETCH| STR2TBL | 1 | 2 | 28 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------
보시다시피 위 계획의 카디널리티는 더 이상 8196 추측 값이 아닙니다. 문자열 리터럴 대신 열을 함수에 전달하기 때문에 여전히 올바르지 않습니다.
이 특정 경우에 더 가까운 추정치를 제공하려면 함수 코드를 약간 조정해야하지만 전체적인 개념이 여기에 설명되어 있다고 생각합니다.
이 답변에 사용 된 str2tbl 함수는 원래 Tom Kyte가 개발했습니다.
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:110612348061
통계를 개체 유형과 연결하는 개념은 다음 기사를 통해 자세히 알아볼 수 있습니다.
http://www.oracle-developer.net/display.php?id=427
여기에 설명 된 기술은 10g +에서 작동합니다.
REGEXP
,XMLTABLE
andMODEL
절을 사용하는 예는 Oracle SQL을 사용하여 테이블에서 쉼표로 구분 된 문자열 분할