ฉันต้องการเสนอแนวทางอื่นโดยใช้ฟังก์ชันตาราง 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
ปัญหาเกี่ยวกับวิธีการประเภทนี้คือบ่อยครั้งที่เครื่องมือเพิ่มประสิทธิภาพจะไม่ทราบความสำคัญของฟังก์ชันตารางและจะต้องคาดเดา ซึ่งอาจเป็นอันตรายต่อแผนการดำเนินการของคุณดังนั้นจึงสามารถขยายโซลูชันนี้เพื่อให้สถิติการดำเนินการสำหรับเครื่องมือเพิ่มประสิทธิภาพ
คุณสามารถดูค่าประมาณของเครื่องมือเพิ่มประสิทธิภาพนี้ได้โดยการเรียกใช้แผนอธิบายในแบบสอบถามด้านบน:
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
และMODEL
ข้อดู ลิตจุลภาคคั่นสตริงในตารางโดยใช้ Oracle SQL