BORU HATLI tablo işlevi kullanarak farklı bir yaklaşım önermek istiyorum. Karakter dizesini bölmek için kendi özel işlevinizi sağlamanız dışında, XMLTABLE tekniğine biraz benzer:
-- 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));
Sonuçlar:
NAME PROJECT ERROR
---------- ---------- --------------------
108 test Err1
108 test Err2
108 test Err3
109 test2 Err1
Bu tür bir yaklaşımla ilgili sorun, çoğu zaman optimize edicinin tablo işlevinin önemini bilmemesi ve bir tahmin yapması gerekmesidir. Bu, yürütme planlarınız için potansiyel olarak zararlı olabilir, bu nedenle bu çözüm, optimize edici için yürütme istatistikleri sağlayacak şekilde genişletilebilir.
Bu optimize edici tahminini yukarıdaki sorguda bir AÇIKLAMA PLANI çalıştırarak görebilirsiniz:
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 |
----------------------------------------------------------------------------------------------
Koleksiyon yalnızca 3 değere sahip olsa da, iyileştirici bunun için 8168 satır tahmin etti (varsayılan değer). Bu ilk bakışta alakasız görünebilir, ancak optimize edicinin optimalin altında bir plana karar vermesi yeterli olabilir.
Çözüm, koleksiyona istatistik sağlamak için optimize edici uzantılarını kullanmaktır:
-- 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;
Ortaya çıkan yürütme planını test etmek:
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 |
----------------------------------------------------------------------------------------------
Gördüğünüz gibi yukarıdaki plandaki önem düzeyi artık 8196'nın tahmin edilen değeri değil. Hala doğru değil çünkü işleve bir dizge yerine bir sütun geçiriyoruz.
Bu özel durumda daha yakın bir tahminde bulunmak için işlev kodunda biraz ince ayar yapılması gerekebilir, ancak genel konseptin burada hemen hemen açıklandığını düşünüyorum.
Bu cevapta kullanılan str2tbl işlevi orijinal olarak Tom Kyte tarafından geliştirilmiştir:
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:110612348061
İstatistikleri nesne türleriyle ilişkilendirme kavramı, bu makaleyi okuyarak daha ayrıntılı incelenebilir:
http://www.oracle-developer.net/display.php?id=427
Burada açıklanan teknik 10g + olarak çalışır.
REGEXP
,XMLTABLE
veMODEL
fıkra, bkz Oracle SQL kullanarak bir tabloya Bölünmüş virgülle ayrılmış dizeleri