<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>TunA</title>
    <link>https://tuna.tistory.com/</link>
    <description>2007년부터 Oracle Database 성능 최적화에 관심을 가져왔습니다. 현재 한국오라클 Engineered Systems Solution Engineering 팀에서 Solution Engineer로 근무하고 있습니다. 이 블로그는 개인적인 연구 목적으로 운영되며 Oracle 사의 공식적인 입장을 대변하지 않습니다.</description>
    <language>ko</language>
    <pubDate>Thu, 21 May 2026 13:54:54 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>정희락</managingEditor>
    <image>
      <title>TunA</title>
      <url>https://tistory1.daumcdn.net/tistory/4372028/attach/a7c8c26b49944e0d953a639a97374244</url>
      <link>https://tuna.tistory.com</link>
    </image>
    <item>
      <title>DBMS_SHARED_POOL.MARKHOT</title>
      <link>https://tuna.tistory.com/215</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;LCO에 대한 과도한 Pin으로 인한 &lt;a style=&quot;text-align: start;&quot; href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/26/refrn/descriptions-of-wait-events.html#GUID-30495444-99D2-401F-AADB-86B114C4E81F&quot;&gt;library cache: mutex X&lt;/a&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp;경합을 해소하기 위해&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;text-align: start;&quot; href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/DBMS_SHARED_POOL.html#GUID-EC3047BF-BA54-4131-9E73-F44BD6FB097D&quot;&gt;DBMS_SHARED_POOL.MARKHOT&lt;/a&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&amp;nbsp;프로시저 적용을 고려할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테스트를 위해 아래와 같이 테이블과 함수를 생성하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757729956355&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1-1
DROP TABLE t1 PURGE;
DROP TABLE t2 PURGE;

CREATE TABLE t1 (c1) AS SELECT ROWNUM FROM XMLTABLE ('1 to 100');
CREATE TABLE t2 (c1) AS SELECT ROWNUM FROM XMLTABLE ('1 to 100');

-- 1-2
CREATE OR REPLACE FUNCTION f1 (i_val IN NUMBER)
    RETURN NUMBER
IS
BEGIN
    RETURN i_val;
END;
/&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래와 같이 f1 함수를 사용하는 SQL 문을 100회 수행하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757729964928&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 2
DECLARE
    v1 NUMBER;
BEGIN
    FOR i IN 1 .. 100 LOOP
        SELECT MAX (f1 (c1)) INTO v1 FROM t1;
    END LOOP;
END;
/&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/refrn/V-DB_OBJECT_CACHE.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;V$DB_OBJECT_CACHE&lt;/a&gt;&amp;nbsp;뷰와&amp;nbsp;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/refrn/V-SQL.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;V$SQL&lt;/a&gt;뷰를 조회한 결과입니다. f1 함수와 SQL 문의 Pin 횟수가 100회이므로 PL/SQL 함수를 사용하는 SQL 문을 수행하면 PL/SQL 함수도 함께 Pin되는 것을 알 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757729977879&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 3-1
SELECT   owner, name, namespace, pinned_total, property, full_hash_value, addr
    FROM v$db_object_cache
   WHERE name IN ('F1', 'SELECT MAX (F1 (C1)) FROM T1')
ORDER BY owner, name, property;

OWNER NAME                         NAMESPACE       PINNED_TOTAL PROPERTY FULL_HASH_VALUE                  ADDR
----- ---------------------------- --------------- ------------ -------- -------------------------------- ----------------
TUNA  F1                           TABLE/PROCEDURE          103          dd6291623780db0a953664812f4c1dba 00007FFC98CCB9A0
      SELECT MAX (F1 (C1)) FROM T1 SQL AREA                   1          36719b0ff905d2831187f72eaca494e4 00007FFC98CB7030 --&amp;gt; PARENT
      SELECT MAX (F1 (C1)) FROM T1 SQL AREA                 101          36719b0ff905d2831187f72eaca494e4 00007FFC98CB58D0 --&amp;gt; CHILD

3 rows selected.

-- 3-2
SELECT sql_id, child_number, parse_calls, address, child_address
  FROM v$sql
 WHERE sql_text = 'SELECT MAX (F1 (C1)) FROM T1';

SQL_ID        CHILD_NUMBER PARSE_CALLS ADDRESS          CHILD_ADDRESS
------------- ------------ ----------- ---------------- ----------------
131zr5uqa9574            0           1 00007FFC98CB7030 00007FFC98CB58D0

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;sys 유저에서 아래와 같이 DBMS_SHARED_POOL.MARKHOT 프로시저를 수행하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757729991191&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 4: sys
EXEC DBMS_SHARED_POOL.MARKHOT (hash =&amp;gt; 'dd6291623780db0a953664812f4c1dba', namespace =&amp;gt; 1);
EXEC DBMS_SHARED_POOL.MARKHOT (hash =&amp;gt; '36719b0ff905d2831187f72eaca494e4', namespace =&amp;gt; 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;재접속 후 아래와 같이 f1 함수를 사용하는 두 SQL 문을 100회씩 수행하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757730003047&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 5: reconnect
DECLARE
    v1 NUMBER;
BEGIN
    FOR i IN 1 .. 100 LOOP
        SELECT MAX (f1 (c1)) INTO v1 FROM t1;
        SELECT MAX (f1 (c1)) INTO v1 FROM t2;
    END LOOP;
END;
/&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;아래는&amp;nbsp;&lt;/span&gt;V$DB_OBJECT_CACHE&amp;nbsp;뷰와&amp;nbsp;V$SQL뷰를 다시 조회한 결과입니다. 앞서 조회한 LCO의 property 값에 HOT이 표시되고, &lt;span style=&quot;text-align: start;&quot;&gt;property 값이&amp;nbsp;&lt;/span&gt;HOCOPY1으로 표시되는 LCO가 새로 생성된 것을 볼 수 있습니다. HOTCOPY의 개수는 _kgl_hot_object_copies 파라미터에 의해 결정되며 기본값은 cpu_count / 2로 알려져 있습니다.&amp;nbsp;t1 테이블을 조회하는 SQL 문은 &lt;span style=&quot;text-align: justify;&quot;&gt;Hot LCO이므로 &lt;/span&gt;SQL ID가 다른 새로운 커서가 생성되는 반면, t2 테이블의 조회하는 SQL 문은 &lt;span style=&quot;text-align: justify;&quot;&gt;Hot LCO인 f1 함수를 사용했지만 &lt;/span&gt;새로운 커서가 생성되지 않은 것을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1757730032093&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 6-1
SELECT   owner, name, namespace, pinned_total, property, full_hash_value, addr
    FROM v$db_object_cache
   WHERE name IN ('F1', 'SELECT MAX (F1 (C1)) FROM T1', 'SELECT MAX (F1 (C1)) FROM T2')
ORDER BY owner, name, property;

OWNER NAME                         NAMESPACE       PINNED_TOTAL PROPERTY FULL_HASH_VALUE                  ADDR
----- ---------------------------- --------------- ------------ -------- -------------------------------- ----------------
TUNA  F1                           TABLE/PROCEDURE          103 HOT      dd6291623780db0a953664812f4c1dba 00007FFC98CCB9A0
TUNA  F1                           TABLE/PROCEDURE          203 HOTCOPY1 cb884c05ca9dbdcbb35d2b51f7f7ebc7 00007FFC98BED440
      SELECT MAX (F1 (C1)) FROM T1 SQL AREA                   1 HOT      36719b0ff905d2831187f72eaca494e4 00007FFC98CB7030 --&amp;gt; PARENT
      SELECT MAX (F1 (C1)) FROM T1 SQL AREA                 101 HOT      36719b0ff905d2831187f72eaca494e4 00007FFC98CB58D0 --&amp;gt; CHILD
      SELECT MAX (F1 (C1)) FROM T1 SQL AREA                   1 HOTCOPY1 aab94c9808a83f0830f45c309d4b6d65 00007FFC98BE9F10 --&amp;gt; PARENT
      SELECT MAX (F1 (C1)) FROM T1 SQL AREA                 101 HOTCOPY1 aab94c9808a83f0830f45c309d4b6d65 00007FFC98BE8480 --&amp;gt; CHILD
      SELECT MAX (F1 (C1)) FROM T2 SQL AREA                   1          e7b5983639afe143bfca644c9e8cceed 00007FFC98BE9BE0 --&amp;gt; PARENT
      SELECT MAX (F1 (C1)) FROM T2 SQL AREA                 101          e7b5983639afe143bfca644c9e8cceed 00007FFC98BE25F0 --&amp;gt; CHILD

8 rows selected.

-- 6-2
SELECT sql_id, child_number, parse_calls, address, child_address
  FROM v$sql
 WHERE sql_text IN ('SELECT MAX (F1 (C1)) FROM T1', 'SELECT MAX (F1 (C1)) FROM T2');

SQL_ID        CHILD_NUMBER PARSE_CALLS ADDRESS          CHILD_ADDRESS
------------- ------------ ----------- ---------------- ----------------
131zr5uqa9574            0           1 00007FFC98CB7030 00007FFC98CB58D0 --&amp;gt; HOT
31x2w62fnqvb5            0           1 00007FFC98BE9F10 00007FFC98BE8480 --&amp;gt; HOTCOPY1
bzkm49kg8tmrd            0           1 00007FFC98BE9BE0 00007FFC98BE25F0

3 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;sys 유저에서 아래와 같이 &lt;a style=&quot;text-align: start;&quot; href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/DBMS_SHARED_POOL.html#GUID-14D8F1BA-D8EE-4838-99C8-E8D7EDA452C9&quot;&gt;DBMS_SHARED_POOL.UNMARKHOT&lt;/a&gt; 프로시저를 수행하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1757730049088&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 7: sys
EXEC DBMS_SHARED_POOL.UNMARKHOT (hash =&amp;gt; 'dd6291623780db0a953664812f4c1dba', namespace =&amp;gt; 1);
EXEC DBMS_SHARED_POOL.UNMARKHOT (hash =&amp;gt; '36719b0ff905d2831187f72eaca494e4', namespace =&amp;gt; 0);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는&amp;nbsp;&lt;span style=&quot;text-align: start;&quot;&gt;V$DB_OBJECT_CACHE&amp;nbsp;뷰와&amp;nbsp;V$SQL뷰를 다시 조회한 결과입니다. &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;HOT LCO의 property 값이 널로 표시되고 HOTCOPY LCO의&amp;nbsp; 값이 OBSCOPY(&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Obsoleted LCO)로 표시되는 것을 볼 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1757730058754&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 8-1
SELECT   owner, name, namespace, pinned_total, property, full_hash_value, addr
    FROM v$db_object_cache
   WHERE name IN ('F1', 'SELECT MAX (F1 (C1)) FROM T1', 'SELECT MAX (F1 (C1)) FROM T2')
ORDER BY owner, name, property;

OWNER NAME                         NAMESPACE       PINNED_TOTAL PROPERTY FULL_HASH_VALUE                  ADDR
----- ---------------------------- --------------- ------------ -------- -------------------------------- ----------------
TUNA  F1                           TABLE/PROCEDURE          104          dd6291623780db0a953664812f4c1dba 00007FFC98CCB9A0
TUNA  F1                           TABLE/PROCEDURE          204 OBSCOPY1 cb884c05ca9dbdcbb35d2b51f7f7ebc7 00007FFC98BED440
      SELECT MAX (F1 (C1)) FROM T1 SQL AREA                   1          36719b0ff905d2831187f72eaca494e4 00007FFC98CB7030 --&amp;gt; PARENT
      SELECT MAX (F1 (C1)) FROM T1 SQL AREA                 101          36719b0ff905d2831187f72eaca494e4 00007FFC98CB58D0 --&amp;gt; CHILD
      SELECT MAX (F1 (C1)) FROM T1 SQL AREA                   1 OBSCOPY1 aab94c9808a83f0830f45c309d4b6d65 00007FFC98BE9F10 --&amp;gt; PARENT
      SELECT MAX (F1 (C1)) FROM T1 SQL AREA                 101 OBSCOPY1 aab94c9808a83f0830f45c309d4b6d65 00007FFC98BE8480 --&amp;gt; CHILD
      SELECT MAX (F1 (C1)) FROM T2 SQL AREA                   1          e7b5983639afe143bfca644c9e8cceed 00007FFC98BE9BE0 --&amp;gt; PARENT
      SELECT MAX (F1 (C1)) FROM T2 SQL AREA                 101          e7b5983639afe143bfca644c9e8cceed 00007FFC98BE25F0 --&amp;gt; CHILD

8 rows selected.

-- 8-2
SELECT sql_id, child_number, parse_calls, address, child_address
  FROM v$sql
 WHERE sql_text IN ('SELECT MAX (F1 (C1)) FROM T1', 'SELECT MAX (F1 (C1)) FROM T2');

SQL_ID        CHILD_NUMBER PARSE_CALLS ADDRESS          CHILD_ADDRESS
------------- ------------ ----------- ---------------- ----------------
131zr5uqa9574            0           1 00007FFC98CB7030 00007FFC98CB58D0 --&amp;gt; HOT
31x2w62fnqvb5            0           1 00007FFC98BE9F10 00007FFC98BE8480 --&amp;gt; HOTCOPY1
bzkm49kg8tmrd            0           1 00007FFC98BE9BE0 00007FFC98BE25F0

3 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;관련 링크&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://juliandontcheff.wordpress.com/2013/02/12/reducing-library-cache-mutex-x-concurrency-with-dbms_shared_pool-markhot&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Julian&amp;nbsp;Dontcheff&amp;nbsp;-&amp;nbsp;Reducing&amp;nbsp;&quot;library&amp;nbsp;cache:&amp;nbsp;mutex&amp;nbsp;X&quot;&amp;nbsp;concurrency&amp;nbsp;with&amp;nbsp;dbms_shared_pool.markhot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jonathanlewis.wordpress.com/2017/10/02/markhot&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Jonathan&amp;nbsp;Lewis&amp;nbsp;-&amp;nbsp;markhot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.pythian.com/blog/technical-track/reducing-contention-on-hot-cursor-objects-cursor-pin-s&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Pythian&amp;nbsp;Blog&amp;nbsp;-&amp;nbsp;Reducing&amp;nbsp;Contention&amp;nbsp;on&amp;nbsp;Hot&amp;nbsp;Cursor&amp;nbsp;Objects&amp;nbsp;(Cursor:&amp;nbsp;Pin&amp;nbsp;S)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Oracle/Performance</category>
      <author>정희락</author>
      <guid isPermaLink="true">https://tuna.tistory.com/215</guid>
      <comments>https://tuna.tistory.com/215#entry215comment</comments>
      <pubDate>Sat, 13 Sep 2025 11:22:08 +0900</pubDate>
    </item>
    <item>
      <title>Exafusion Direct-to-Wire Protocol</title>
      <link>https://tuna.tistory.com/214</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.oracle.com/database/technologies/exadata/software/exafusion&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Exafusion&amp;nbsp;Direct-to-Wire&amp;nbsp;Protocol&lt;/a&gt;은 RAC 환경에서 OS와 네트워크 계층을 우회하여 인스턴스 간에 직접 메시지를 보내고 받을 수 있는 Exadata 전용 프로토콜입니다. Oracle 21c부터 Cache Fusion에 대한 RDMA 지원이 확장되어 데이터 블록, 공간 블록, 언두 헤더 블록에 대한 읽기를 지원합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/refrn/descriptions-of-wait-events.html#GUID-A6288D90-9DA9-4BC5-B469-5ABCBAA20FE7&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;gc&amp;nbsp;cr&amp;nbsp;block&amp;nbsp;direct&amp;nbsp;read&lt;/a&gt;, gc current block direct read 대기 이벤트로 Exafusion Direct-to-Wire Protocol의 동작 여부를 판단할 수 있습니다. 아래 쿼리의 결과에서 gc cr block 2-way 대기 이벤트의 평균 대기 시간이 0.15ms인 반면 gc cr block direct read 대기 이벤트의 평균 대기 시간은 8.44us인 것을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1755737050557&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1
SELECT   event
       , total_waits
       , time_waited_micro
       , ROUND (time_waited_micro / total_waits, 2) AS avg_waits
    FROM v$system_event
   WHERE event IN (
             'gc cr block 2-way'
           , 'gc cr block 3-way'
           , 'gc cr block direct read'
           , 'gc current block 2-way'
           , 'gc current block 3-way'
           , 'gc current block direct read'
         )
ORDER BY event;

EVENT                        TOTAL_WAITS TIME_WAITED_MICRO  AVG_WAITS
---------------------------- ----------- ----------------- ----------
gc cr block 2-way                 199216          29720439     149.19 --&amp;gt; 0.15ms
gc cr block direct read          2339003          19751012       8.44 --&amp;gt; 8.44us
gc current block 2-way            388030          44333200     114.25 --&amp;gt; 0.11ms
gc current block direct read      385380           3661325       9.50 --&amp;gt; 9.50us

4 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;관련 링크&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oracle.com/a/ocom/docs/database/rac-cache-fusion-performance-optimizations-on-exadata.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oracle Real Application Clusters (RAC) Optimizations on Exadata&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Exadata</category>
      <category>21c</category>
      <author>정희락</author>
      <guid isPermaLink="true">https://tuna.tistory.com/214</guid>
      <comments>https://tuna.tistory.com/214#entry214comment</comments>
      <pubDate>Thu, 21 Aug 2025 09:52:07 +0900</pubDate>
    </item>
    <item>
      <title>UUID 함수</title>
      <link>https://tuna.tistory.com/213</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Oracle 23ai(&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/nfcoa/ru_23_9.html#GUID-104823-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;23.9&lt;/a&gt;)에 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/uuid.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;UUID&lt;/a&gt; 함수가 추가되었습니다. UUID 함수는 &lt;a href=&quot;https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;version&amp;nbsp;4&amp;nbsp;variant&amp;nbsp;1&amp;nbsp;UUID&lt;/a&gt;를 RAW(16) 형식의 값으로 반환합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 UUID 함수를 사용한 예제입니다. UUID 함수는 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/SYS_GUID.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SYS_GUID&lt;/a&gt; 함수와 달리 로우 별로 다른 값을 반환합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752761343702&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1
SELECT UUID () AS uuid
     , SYS_GUID () AS sys_guid
  FROM XMLTABLE ('1 to 2');

UUID                             SYS_GUID
-------------------------------- --------------------------------
67674554354B4FD7BF7EDEB601A3B609 3A1B91494C76C2DAE0630B01011ECAAB
ECB1CEEDB1214F65BFB8325AE83D4807 3A1B91494C77C2DAE0630B01011ECAAB

2 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트를 위해 아래와 같이 테이블을 생성하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752761421578&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 2
DROP TABLE t1 PURGE;
CREATE TABLE t1 (c1) AS SELECT ROWNUM FROM XMLTABLE ('1 to 10000000');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예제는 UUID 함수, SYS_GUID 함수, &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/ORA_HASH.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ORA_HASH&lt;/a&gt; 함수, &lt;span style=&quot;text-align: start;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/DBMS_RANDOM.html#GUID-AAD9E936-D74F-440D-9E16-24F3F0DE8D31&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DBMS_RANDOM.VALUE&lt;/a&gt; 함수&lt;/span&gt;의 수행 시간을 보여줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752761463818&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 3-1
SELECT COUNT (UUID ()) FROM t1;

Elapsed: 00:00:09.89

-- 3-2
SELECT COUNT (SYS_GUID ()) FROM t1;

Elapsed: 00:00:00.48

-- 3-3
SELECT COUNT (ORA_HASH (c1)) FROM t1;

Elapsed: 00:00:00.99

-- 3-4
SELECT COUNT (DBMS_RANDOM.VALUE) FROM t1;

Elapsed: 00:00:10.65&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Oracle/SQL</category>
      <category>23ai</category>
      <author>정희락</author>
      <guid isPermaLink="true">https://tuna.tistory.com/213</guid>
      <comments>https://tuna.tistory.com/213#entry213comment</comments>
      <pubDate>Thu, 17 Jul 2025 23:11:36 +0900</pubDate>
    </item>
    <item>
      <title>INSERT SET 절과 BY NAME POSITION 절</title>
      <link>https://tuna.tistory.com/212</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Oracle 23ai(&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/nfcoa/ru_23_9.html#GUID-104667-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;23.9&lt;/a&gt;)부터 INSERT 문에 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423__GUID-DA7CDAE4-4689-41A2-B970-18C735712A0E&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;INSERT SET&lt;/a&gt; 절과 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/INSERT.html#GUID-903F8043-0254-4EE9-ACC1-CB8AC0AF3423__GUID-539BB4C8-CDBA-47A3-899A-13984AF90BA4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;BY NAME POSITION&lt;/a&gt;&amp;nbsp;절을 사용할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테스트를 위해 아래와 같이 테이블을 생성하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752760550472&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1
DROP TABLE t1 PURGE;
DROP TABLE t2 PURGE;

CREATE TABLE t1 (c1 NUMBER, c2 NUMBER);
CREATE TABLE t2 (c1 NUMBER, c2 NUMBER, c3 NUMBER);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 INSERT 문에 INSERT SET 절을 사용한 예제입니다. INSERT VALUES 절보다 명시적으로 칼럼과 값을 지정할 수 있어 오류 가능성을 줄일 수 있습니다. 주석 처리된 형식으로도 INSERT SET 절을 사용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752760559510&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 2-1
INSERT INTO t1 SET c1 = 1, c2 = 2;
-- INSERT INTO t1 SET (c1 = 1, c2 = 2);
-- INSERT INTO t1 SET (c1 = 1, c2 = 2), (c1 = 3, c2 = 4);

-- 2-2
SELECT * FROM t1;

C1 C2
-- --
 1  2

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 INSERT 문에 BY NAME POSITION 절을 사용한 예제입니다. 기본값은 BY POSITION입니다. SELECT 절의 표현식에 별칭을 사용하지 않거나&amp;nbsp;INSERT 문의 칼럼 리스트와 SELECT 절의 칼럼 명이 일치하지 않으면 에러가 발생합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752760586878&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 3-1: BY { NAME | POSITION }
INSERT INTO t2 (c1, c2, c3) BY NAME SELECT c2, c1, c1 + c2 AS c3 FROM t1;

-- 3-2
SELECT * FROM t2;

C1 C2 C3
-- -- --
 1  2  3

1 row selected.

-- 3-3
INSERT INTO t2 (c1, c2, c3) BY NAME SELECT c2, c1, c1 + c2 FROM t1;

ORA-63875: Non-aliased expressions or constants are not allowed in a BY NAME clause.

-- 3-4
INSERT INTO t2 (c1, c2, c3) BY NAME SELECT c2, c1, c1 + c2 AS c4 FROM t1;

ORA-63877: The explicit column list does not exactly match the exposed column names.&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Oracle/SQL</category>
      <category>23ai</category>
      <author>정희락</author>
      <guid isPermaLink="true">https://tuna.tistory.com/212</guid>
      <comments>https://tuna.tistory.com/212#entry212comment</comments>
      <pubDate>Thu, 17 Jul 2025 23:02:04 +0900</pubDate>
    </item>
    <item>
      <title>GROUP BY ALL</title>
      <link>https://tuna.tistory.com/211</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Oracle 23ai(&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/nfcoa/ru_23_9.html#GUID-102576-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;23.9&lt;/a&gt;)부터 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/SELECT.html#GUID-CFA006CA-6FF1-4972-821E-6996142A51C6__UL_CNH_LBW_RFC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GROUP BY ALL&lt;/a&gt; 절을 사용할 수 있습니다. GROUP BY ALL 절을 사용하면 집계 함수를 사용하지 않은 표현식을 기준으로 결과가 그룹핑됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테스트를 위해 아래와 같이 테이블을 생성하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752753819289&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1
DROP TABLE t1 PURGE;
CREATE TABLE t1 (c1, c2) AS SELECT CEIL (ROWNUM / 100), CEIL (ROWNUM / 10) FROM XMLTABLE ('1 to 1000');&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 GROUP BY ALL 절을 사용한 예제입니다. 집계 함수를 사용하지 않은 표현식을 기준으로 결과가 그룹핑되는 것을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752753832774&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 2-1
SELECT COUNT (*) AS cnt FROM t1 GROUP BY ALL;

 CNT
----
1000

1 row selected.

-- 2-2
SELECT c1, COUNT (*) AS cnt FROM t1 GROUP BY ALL;

C1 CNT
-- ---
 1 100
...
10 100

10 rows selected.

-- 2-3
SELECT c1, c2, COUNT (*) AS cnt FROM t1 GROUP BY ALL;

C1  C2 CNT
-- --- ---
 1   1  10
...
10 100  10

100 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 결과에서 GROUP BY ALL 절이 Query Transformation에 의해 처리되지 않음을 유추할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1752753901379&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 3-1
SET SERVEROUT ON

DECLARE
    v_output_sql_text CLOB;
BEGIN
    DBMS_UTILITY.EXPAND_SQL_TEXT (
        input_sql_text  =&amp;gt; 'SELECT c1, c2, COUNT (*) AS cnt FROM t1 GROUP BY ALL'
      , output_sql_text =&amp;gt; v_output_sql_text
    );

    DBMS_OUTPUT.PUT_LINE (v_output_sql_text);
END;
/
SELECT &quot;A1&quot;.&quot;C1&quot; &quot;C1&quot;,&quot;A1&quot;.&quot;C2&quot; &quot;C2&quot;,COUNT(*) &quot;CNT&quot; FROM &quot;C##TUNA&quot;.&quot;T1&quot; &quot;A1&quot; GROUP BY &quot;A1&quot;.&quot;C1&quot;,&quot;A1&quot;.&quot;C2&quot;

-- 3-2: 10053 trace
Query after VW_MRG2:
 qb SEL$1 (#0):******* UNPARSED QUERY IS *******

SELECT &quot;T1&quot;.&quot;C1&quot; &quot;C1&quot;,&quot;T1&quot;.&quot;C2&quot; &quot;C2&quot;,COUNT(*) &quot;CNT&quot; FROM &quot;C##TUNA&quot;.&quot;T1&quot; &quot;T1&quot; GROUP BY &quot;T1&quot;.&quot;C1&quot;,&quot;T1&quot;.&quot;C2&quot;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Oracle/SQL</category>
      <category>23ai</category>
      <author>정희락</author>
      <guid isPermaLink="true">https://tuna.tistory.com/211</guid>
      <comments>https://tuna.tistory.com/211#entry211comment</comments>
      <pubDate>Thu, 17 Jul 2025 22:44:18 +0900</pubDate>
    </item>
    <item>
      <title>Hybrid Vector Index</title>
      <link>https://tuna.tistory.com/210</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Oracle 23ai(23.6)에 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/manage-hybrid-vector-indexes.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;하이브리드 벡터 인덱스&lt;/a&gt; 기능이 추가되었습니다. 하이브리드 벡터 인덱스를 사용하하면 전체 텍스트 검색(full-text search)과 벡터 유사도 검색(vector similarity search)을 조합하여 데이터를 조회할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테스트를 위해 예제 데이터를 &lt;a href=&quot;https://cdn.openai.com/API/examples/data/vector_database_wikipedia_articles_embedded.zip&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다운로드&lt;/a&gt;하고 아래와 같이 압축을 해제하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1751070363457&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ unzip /home/oracle/wiki/vector_database_wikipedia_articles_embedded.zip
Archive:  vector_database_wikipedia_articles_embedded.zip
  inflating: vector_database_wikipedia_articles_embedded.csv
  inflating: __MACOSX/._vector_database_wikipedia_articles_embedded.csv&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래와 같이 External 테이블를 사용하여 vector_database_wikipedia_articles_embedded.csv 파일을 wiki 테이블로 적재하겠습니다. 적재된 로우 수는 25,000 건입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1751070402609&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1-1
DROP DIRECTORY dir_wiki;

CREATE DIRECTORY dir_wiki AS '/home/oracle/wiki';

-- 1-2
DROP TABLE ext_wiki PURGE;

CREATE TABLE ext_wiki (
    id             NUMBER
  , url            VARCHAR2(200)
  , title          VARCHAR2(100)
  , text           CLOB
  , title_vector   CLOB
  , content_vector CLOB
  , vector_id      NUMBER
)
ORGANIZATION EXTERNAL (
    TYPE ORACLE_LOADER
    DEFAULT DIRECTORY dir_wiki
    ACCESS PARAMETERS (
        RECORDS
        SKIP 1
        FIELDS CSV WITH EMBEDDED
        MISSING FIELD VALUES ARE NULL (
            id
          , url
          , title
          , text           CHAR(1000000000)
          , title_vector   CHAR(1000000000)
          , content_vector CHAR(1000000000)
          , vector_id
        )
    )
    LOCATION ('vector_database_wikipedia_articles_embedded.csv')
);

-- 1-3
DROP TABLE wiki PURGE;

CREATE TABLE wiki AS SELECT id, url, title, text FROM ext_wiki;

-- 1-4
SELECT COUNT (*) AS cnt FROM wiki;

  CNT
-----
25000

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하이브리드 벡터 인덱스는 벡터 검색, 텍스트 검색, 인덱스 유지 관리에 대한 설정을 할 수 있습니다. 아래와 같이 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/create_preference.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DBMS_VECTOR_CHAIN.CREATE_PREFERENCE&lt;/a&gt; 프로시저로 &lt;span style=&quot;text-align: left;&quot;&gt;하이브리드 벡터 인덱스에 대한 v&lt;span style=&quot;text-align: left;&quot;&gt;ectorizer preference를 생성하고, &lt;a style=&quot;text-align: justify;&quot; href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/create-hybrid-vector-index.html&quot;&gt;CREATE HYBRID VECTOR INDEX&lt;/a&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;문으로 하이브리드 벡터 인덱스를 생성하겠습니다. (&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;25,000 건에 대해 64 DOP로 7분이 소요됨) &lt;span style=&quot;text-align: justify;&quot;&gt;예제에 사용한&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;all_minilm_l12_v2 모델은&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://tuna.tistory.com/195&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ONNX Model&lt;/a&gt;&lt;span style=&quot;text-align: justify;&quot;&gt;&amp;nbsp;글을 참고하세요.&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751070444032&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 2-1
-- CREATE HYBRID VECTOR INDEX wiki_x1 ON wiki (text) PARAMETERS ('MODEL all_minilm_l12_v2');

-- 2-2: set as default
BEGIN
    DBMS_VECTOR_CHAIN.CREATE_PREFERENCE (
        pref_name =&amp;gt; 'WIKI_PREF'
      , pref_type =&amp;gt; DBMS_VECTOR_CHAIN.VECTORIZER
      , params    =&amp;gt; JSON (
            '{
                 &quot;model&quot;: &quot;all_minilm_l12_v2&quot;,
                 &quot;by&quot;: &quot;words&quot;,
                 &quot;max&quot;: 100,
                 &quot;split&quot;: &quot;recursively&quot;,
                 &quot;overlap&quot;: 0,
                 &quot;distance&quot;: &quot;cosine&quot;,
                 &quot;accuracy&quot;: 95,
                 &quot;vector_idxtype&quot;: &quot;ivf&quot;
             }'
        ));
END;
/

-- 2-3
DROP INDEX wiki_x1 FORCE;

CREATE HYBRID VECTOR INDEX wiki_x1 ON wiki (text) PARAMETERS ('VECTORIZER wiki_pref');&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;하이브리드 벡터 인덱스는 도메인 인덱스로 생성되며 다수의 보조 테이블이 자동 생성됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1751070461948&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 3-1
SELECT table_name, index_name, index_type, index_subtype
  FROM user_indexes
 WHERE index_name LIKE '%WIKI%';

TABLE_NAME    INDEX_NAME     INDEX_TYPE INDEX_SUBTYPE
------------- -------------- ---------- -----------------------
WIKI          WIKI_X1        DOMAIN
DR$WIKI_X1$D  DR$WIKI_X1$DI  NORMAL
DR$WIKI_X1$G  DR$WIKI_X1$H   NORMAL
DR$WIKI_X1$I  DR$WIKI_X1$X   NORMAL
DR$WIKI_X1$K  DR$WIKI_X1$KD  NORMAL
DR$WIKI_X1$K  DR$WIKI_X1$KR  NORMAL
DR$WIKI_X1$N  DR$WIKI_X1$NI  NORMAL
DR$WIKI_X1$U  DR$WIKI_X1$UI  NORMAL
DR$WIKI_X1$VR DR$WIKI_X1$VI  VECTOR     NEIGHBOR_PARTITIONS_IVF
DR$WIKI_X1$VR DR$WIKI_X1$VRI NORMAL

10 rows selected.

-- 3-2
SELECT table_name, partitioned, secondary
  FROM user_tables
 WHERE table_name LIKE '%WIKI%';

TABLE_NAME                                                      PARTITIONED SECONDARY
--------------------------------------------------------------- ----------- ---------
EXT_WIKI                                                        NO          N
WIKI                                                            NO          N
DR$WIKI_X1$B                                                    NO          Y
DR$WIKI_X1$C                                                    NO          Y
DR$WIKI_X1$D                                                    NO          Y
DR$WIKI_X1$G                                                    NO          Y
DR$WIKI_X1$I                                                    NO          Y
DR$WIKI_X1$K                                                    NO          Y
DR$WIKI_X1$N                                                    NO          Y
DR$WIKI_X1$Q                                                    NO          Y
DR$WIKI_X1$U                                                    NO          Y
DR$WIKI_X1$VR                                                   NO          Y
VECTOR$DR$WIKI_X1$VI$65402_65413_0$IVF_FLAT_CENTROIDS           NO          N
VECTOR$DR$WIKI_X1$VI$65402_65413_0$IVF_FLAT_CENTROID_PARTITIONS YES         N

14 rows selected.

-- 3-3
SELECT view_name
  FROM user_views
 WHERE view_name LIKE '%WIKI%';

VIEW_NAME
---------------
WIKI_X1$VECTORS

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;wiki_x1$vectors 뷰를 조회하면 청크 정보를 조회할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1751070493271&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 4-1
SELECT *
  FROM wiki
 WHERE id = 1;

ID URL                                     TITLE TEXT
-- --------------------------------------- ----- --------------------------------------------------------------------------------
 1 https://simple.wikipedia.org/wiki/April April April is the fourth month of the year in the Julian and Gregorian calendars, ...

1 row selected.

-- 4-2
SELECT *
  FROM wiki_x1$vectors
 WHERE DOC_ROWID = (SELECT ROWID FROM wiki WHERE id = 1);

DOC_ROWID          DOC_CHUNK_ID DOC_CHUNK_COUNT DOC_CHUNK_OFFSET DOC_CHUNK_LENGTH DOC_CHUNK_TEXT                   DOC_CHUNK_EMBEDDING
------------------ ------------ --------------- ---------------- ---------------- -------------------------------- ---------------------
AAAP9lAAAAABAArAAA            1              40                1              437 April is the fourth month of ... [-8.13307762E-002,...
AAAP9lAAAAABAArAAA            2              40              438              205 April comes between March and... [2.67323982E-002,...
...
40 rows selected.

---------------------------------------------------------
| Id  | Operation                       | Name          |
---------------------------------------------------------
|   0 | SELECT STATEMENT                |               |
|*  1 |  HASH JOIN RIGHT ANTI NA        |               |
|   2 |   VIEW                          | VW_NSO_1      |
|*  3 |    FILTER                       |               |
|   4 |     SORT GROUP BY               |               |
|*  5 |      VIEW                       |               |
|   6 |       WINDOW SORT               |               |
|   7 |        TABLE ACCESS STORAGE FULL| DR$WIKI_X1$C  |
|*  8 |   HASH JOIN                     |               |
|   9 |    TABLE ACCESS STORAGE FULL    | DR$WIKI_X1$K  |
|  10 |    TABLE ACCESS STORAGE FULL    | DR$WIKI_X1$VR |
---------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/search.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DBMS_HYBRID_VECTOR.SEARCH&lt;/a&gt; 함수로 What have scientists discovered? 검색 키워드와 elements 텍스트가 포함된 상위 5개의 로우를 조회합니다. &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;ROWID, 점수, 벡터 점수, 텍스트 점수가 포함된 &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;JSON 값이 반환됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1751070508008&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 5
SELECT JSON_SERIALIZE (DBMS_HYBRID_VECTOR.SEARCH (JSON (
           '{
                &quot;hybrid_index_name&quot;: &quot;wiki_x1&quot;,
                &quot;search_scorer&quot;: &quot;rsf&quot;,
                &quot;search_fusion&quot;: &quot;INTERSECT&quot;,
                &quot;vector&quot;: {
                    &quot;search_text&quot;: &quot;What have scientists discovered?&quot;,
                    &quot;search_mode&quot;: &quot;DOCUMENT&quot;,
                    &quot;aggregator&quot;: &quot;MAX&quot;,
                    &quot;score_weight&quot;: 1
                },
                &quot;text&quot;: {
                    &quot;contains&quot;: &quot;$elements&quot;,
                    &quot;score_weight&quot;: 1
                },
                &quot;return&quot;: {
                    &quot;values&quot;: [&quot;rowid&quot;, &quot;score&quot;, &quot;vector_score&quot;, &quot;text_score&quot;],
                    &quot;topN&quot;: 5
                }
            }'
       )) RETURNING CLOB PRETTY) AS result;

RESULT
-----------------------------------
[
  {
    &quot;rowid&quot; : &quot;AAAP9lAAAAABAAuAAE&quot;,
    &quot;score&quot; : 56.7,
    &quot;vector_score&quot; : 64.4,
    &quot;text_score&quot; : 49
  },
  {
    &quot;rowid&quot; : &quot;AAAP9lAAAAABAA0AAI&quot;,
    &quot;score&quot; : 53.24,
    &quot;vector_score&quot; : 65.48,
    &quot;text_score&quot; : 41
  },
  {
    &quot;rowid&quot; : &quot;AAAP9lAAAAABAB3AAC&quot;,
    &quot;score&quot; : 53.16,
    &quot;vector_score&quot; : 65.32,
    &quot;text_score&quot; : 41
  },
  {
    &quot;rowid&quot; : &quot;AAAP9lAAAAABAGUAAA&quot;,
    &quot;score&quot; : 47.83,
    &quot;vector_score&quot; : 71.66,
    &quot;text_score&quot; : 24
  },
  {
    &quot;rowid&quot; : &quot;AAAP9lAAAAABABGAAH&quot;,
    &quot;score&quot; : 45.82,
    &quot;vector_score&quot; : 67.64,
    &quot;text_score&quot; : 24
  }
]

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/JSON_TABLE.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JSON_TABLE&lt;/a&gt; 함수를 사용하여 하이브리드 벡터 인덱스 검색 결과와 wiki 테이블을 조인한 결과를 보여줍니다. cnt 열은 text 칼럼에 elements 텍스트가 포함된 개수를 나타냅니다.&lt;/p&gt;
&lt;pre id=&quot;code_1751070519271&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 6
SELECT b.score, b.vector_score, b.text_score, c.id, c.url, c.title, REGEXP_COUNT (c.text, 'elements') AS cnt
  FROM (SELECT DBMS_HYBRID_VECTOR.SEARCH (JSON (
                   '{
                        &quot;hybrid_index_name&quot;: &quot;wiki_x1&quot;,
                        &quot;search_scorer&quot;: &quot;rsf&quot;,
                        &quot;search_fusion&quot;: &quot;INTERSECT&quot;,
                        &quot;vector&quot;: {
                            &quot;search_text&quot;: &quot;What have scientists discovered?&quot;,
                            &quot;search_mode&quot;: &quot;DOCUMENT&quot;,
                            &quot;aggregator&quot;: &quot;MAX&quot;,
                            &quot;score_weight&quot;: 1
                        },
                        &quot;text&quot;: {
                            &quot;contains&quot;: &quot;$elements&quot;,
                            &quot;score_weight&quot;: 1
                        },
                        &quot;return&quot;: {
                            &quot;values&quot;: [&quot;rowid&quot;, &quot;score&quot;, &quot;vector_score&quot;, &quot;text_score&quot;],
                            &quot;topN&quot;: 5
                        }
                    }'
               )) AS result) a
     , JSON_TABLE (a.result, '$[*]' COLUMNS (
                       rid          VARCHAR2(18) PATH '$.rowid'
                     , score        NUMBER       PATH '$.score'
                     , vector_score NUMBER       PATH '$.vector_score'
                     , text_score   NUMBER       PATH '$.text_score'
                   )) b
     , wiki c
 WHERE c.rowid = b.rid;

SCORE VECTOR_SCORE TEXT_SCORE   ID URL                                         TITLE     CNT
----- ------------ ---------- ---- ------------------------------------------- --------- ---
56.70        64.40         49   47 https://simple.wikipedia.org/wiki/Atom      Atom       10
53.24        65.48         41  108 https://simple.wikipedia.org/wiki/Chemistry Chemistry   8
53.16        65.32         41  858 https://simple.wikipedia.org/wiki/Universe  Universe    6
47.83        71.66         24 2949 https://simple.wikipedia.org/wiki/Oxygen    Oxygen      5
45.82        67.64         24  357 https://simple.wikipedia.org/wiki/Helium    Helium      3

5 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 What have scientists discovered? 검색 키워드만 포함된 상위 5개의 로우를 조회합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1751070529960&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 7
SELECT JSON_SERIALIZE (DBMS_HYBRID_VECTOR.SEARCH (JSON (
           '{
                &quot;hybrid_index_name&quot;: &quot;wiki_x1&quot;,
                &quot;search_scorer&quot;: &quot;rsf&quot;,
                &quot;search_fusion&quot;: &quot;INTERSECT&quot;,
                &quot;vector&quot;: {
                    &quot;search_text&quot;: &quot;What have scientists discovered?&quot;,
                    &quot;search_mode&quot;: &quot;DOCUMENT&quot;,
                    &quot;aggregator&quot;: &quot;MAX&quot;,
                    &quot;score_weight&quot;: 1
                },
                &quot;return&quot;: {
                    &quot;values&quot;: [&quot;rowid&quot;, &quot;score&quot;, &quot;vector_score&quot;],
                    &quot;topN&quot;: 5
                }
            }'
       )) RETURNING CLOB PRETTY) AS result;

RESULT
-----------------------------------
[
  {
    &quot;rowid&quot; : &quot;AAAP9lAAAAABAKoAAC&quot;,
    &quot;score&quot; : 74.61,
    &quot;vector_score&quot; : 74.61
  },
  {
    &quot;rowid&quot; : &quot;AAAP9lAAAAABBVqAAF&quot;,
    &quot;score&quot; : 74.61,
    &quot;vector_score&quot; : 74.61
  },
  {
    &quot;rowid&quot; : &quot;AAAP9lAAAAABAVTAAA&quot;,
    &quot;score&quot; : 71.96,
    &quot;vector_score&quot; : 71.96
  },
  {
    &quot;rowid&quot; : &quot;AAAP9lAAAAABBUCAAB&quot;,
    &quot;score&quot; : 71.66,
    &quot;vector_score&quot; : 71.66
  },
  {
    &quot;rowid&quot; : &quot;AAAP9lAAAAABAB3AAF&quot;,
    &quot;score&quot; : 71.66,
    &quot;vector_score&quot; : 71.66
  }
]

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;id가 882인 로우의 text 칼럼에만 elements 텍스트가 포함된 것을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1751070541150&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 8
SELECT b.score, b.vector_score, c.id, c.url, c.title, REGEXP_COUNT (c.text, 'elements') AS cnt
  FROM (SELECT DBMS_HYBRID_VECTOR.SEARCH (JSON (
                   '{
                        &quot;hybrid_index_name&quot;: &quot;wiki_x1&quot;,
                        &quot;search_scorer&quot;: &quot;rsf&quot;,
                        &quot;search_fusion&quot;: &quot;INTERSECT&quot;,
                        &quot;vector&quot;: {
                            &quot;search_text&quot;: &quot;What have scientists discovered?&quot;,
                            &quot;search_mode&quot;: &quot;DOCUMENT&quot;,
                            &quot;aggregator&quot;: &quot;MAX&quot;,
                            &quot;score_weight&quot;: 1
                        },
                        &quot;return&quot;: {
                            &quot;values&quot;: [&quot;rowid&quot;, &quot;score&quot;, &quot;vector_score&quot;],
                            &quot;topN&quot;: 5
                        }
                    }'
               )) AS result) a
     , JSON_TABLE (a.result, '$[*]' COLUMNS (
                       rid          VARCHAR2(18) PATH '$.rowid'
                     , score        NUMBER       PATH '$.score'
                     , vector_score NUMBER       PATH '$.vector_score'
                   )) b
     , wiki c
 WHERE c.rowid = b.rid;

SCORE VECTOR_SCORE    ID URL                                                TITLE            CNT
----- ------------ ----- -------------------------------------------------- ---------------- ---
74.61        74.61  5757 https://simple.wikipedia.org/wiki/Virus            Virus              0
74.61        74.61 57419 https://simple.wikipedia.org/wiki/Caecilian        Caecilian          0
71.96        71.96 18125 https://simple.wikipedia.org/wiki/Phenomenon       Phenomenon         0
71.66        71.66 55347 https://simple.wikipedia.org/wiki/Neurotransmitter Neurotransmitter   0
71.66        71.66   882 https://simple.wikipedia.org/wiki/Uranus           Uranus             1

5 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 5번 예제와 7번 예제의 세션 통계를 비교한 결과입니다. 텍스트 검색의 유무에 따라 세션 통계에 차이가 발생한 것을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1751070550743&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 9
+----------------------+--------+--------+-------+------+------+
|NAME                  |      #5|      #7|   DIFF| RATIO|CLASS |
+----------------------+--------+--------+-------+------+------+
|recursive calls       |      23|      13|    -10|  0.57|User  |
|session logical reads |   2,694|   1,987|   -707|  0.74|User  |
|user calls            |      27|      24|     -3|  0.89|User  |
|execute count         |      22|      16|     -6|  0.73|SQL   |
|parse count (total)   |      10|       6|     -4|  0.60|SQL   |
|sorts (rows)          |   8,312|   6,500| -1,812|  0.78|SQL   |
+----------------------+--------+--------+-------+------+------+&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;관련 링크&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://blogs.oracle.com/database/post/using-hybrid-vector-indexes&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oracle Blog - Using Hybrid Vector Indexes in AI Vector Search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blogs.oracle.com/coretec/post/hybrid-vector-index-the-combination-of-full-text-and-semantic-vector-search&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oracle Blog - Hybrid Vector Index - a combination of AI Vector Search with Text Search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blogs.oracle.com/coretec/post/more-examples-on-hybrid-vector-search&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oracle Blog - More Examples on Hybrid Vector Search&lt;/a&gt; (2025-08-13)&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Oracle/Vector</category>
      <category>23ai</category>
      <author>정희락</author>
      <guid isPermaLink="true">https://tuna.tistory.com/210</guid>
      <comments>https://tuna.tistory.com/210#entry210comment</comments>
      <pubDate>Sat, 28 Jun 2025 09:29:21 +0900</pubDate>
    </item>
    <item>
      <title>TIME_BUCKET 함수</title>
      <link>https://tuna.tistory.com/209</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Oracle 23ai(23.7)에 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/nfcoa/ru_23_7.html#GUID-100396-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SQL Time Bucketing&lt;/a&gt; 기능이 추가되었습니다. 이 기능을 사용하면 시계열 데이터를 특정 간격(버킷)으로 집계 분석할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/time_bucket-datetime.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TIME_BUCKET&lt;/a&gt; 함수는 입력 날짜 값를 특정 원점에 맞춰 지정된 간격으로 버킷화하여 버킷의 시작 부분을 반환합니다. 아래는 TIME_BUCKET 함수의 구문입니다. 첫 번째 인수는 입력 날짜 값, 두 번째 인수는 간격, 세 번째 인수는 원점, 네 번째 인수는 버킷의 시작 또는 끝을 반환할지 여부(기본값은 START), 다섯 번째 인수는 월말일에 대해 버킷을 결정하는 방식(기본값은 ON OVERFLOW ROUND)을 입력합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1749374710552&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;TIME_BUCKET (datetime, stride, origin, [ START | END ] [ ON OVERFLOW { ROUND | ERROR } | LAST DAY OF MONTH ])&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;두 번째 인수는 INTERVAL YEAR TO MONTH, INTERVAL DAY TO SECOND, ISO 8601 시간 인터벌 문자열 형식으로 입력할 수 있습니다. 아래는 ISO 8601 시간 인터벌 문자열 형식의 구문입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749374720330&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[-]P[yearsY][monthsM][daysD][T[hoursH][minutesM][seconds[.fac_secs]S]]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;다섯 번째 인수는 아래와 같이 동작합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ON OVERFLOW ROUND: 해당 월의 원점과 같은 날에 반올림 (해당 날짜가 없는 월의 경우 해당 월의 마지막 날로 반올림)&lt;/li&gt;
&lt;li&gt;ON OVERFLOW ERROR: 해당 월의 원점과 같은 날로 잘림 (해당 날짜가 없는 월의 경우 오류 발생)&lt;/li&gt;
&lt;li&gt;LAST DAY OF MONTH: 원점이 해당 월의 마지막 날이고 범위에 월 또는 년만 포함된 경우 해당 월의 마지막 날로 잘림&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테스트를 위해 아래와 같이 테이블을 생성하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749374835120&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1
DROP TABLE t1 PURGE;
DROP TABLE t2 PURGE;

CREATE TABLE t1 (c1) AS
SELECT DATE '2050-01-01' + NUMTODSINTERVAL (ROWNUM - 1, 'SECOND')
  FROM XMLTABLE ('1 to 7200');

CREATE TABLE t2 (c1) AS
SELECT DATE '2050-01-01' + NUMTODSINTERVAL (ROWNUM - 1, 'DAY')
  FROM XMLTABLE ('1 to 1000')
 WHERE DATE '2050-01-01' + NUMTODSINTERVAL (ROWNUM - 1, 'DAY') &amp;lt; DATE '2052-01-01';&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 원점이 00:00:00이고 간격이 10분인 버킷으로 데이터를 집계한 결과를 보여줍니다. 네 번째 인수가 END면 다음 버킷의 시작 값을 반환합니다. 즉, 버킷에는 시작 이상, 끝 미만인 데이터가 포함됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749374851090&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 2
SELECT   TIME_BUCKET (c1, 'PT10M', TO_DATE ('0001-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')) AS start_dt
       , TIME_BUCKET (c1, 'PT10M', TO_DATE ('0001-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), END) AS end_dt
       , MIN (c1) AS min_dt, MAX (c1) AS max_dt, COUNT (*) AS cnt
    FROM t1
GROUP BY TIME_BUCKET (c1, 'PT10M', TO_DATE ('0001-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'))
       , TIME_BUCKET (c1, 'PT10M', TO_DATE ('0001-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'), END);

START_DT            END_DT              MIN_DT              MAX_DT              CNT
------------------- ------------------- ------------------- ------------------- ---
2050-01-01 00:00:00 2050-01-01 00:10:00 2050-01-01 00:00:00 2050-01-01 00:09:59 600
2050-01-01 00:10:00 2050-01-01 00:20:00 2050-01-01 00:10:00 2050-01-01 00:19:59 600
2050-01-01 00:20:00 2050-01-01 00:30:00 2050-01-01 00:20:00 2050-01-01 00:29:59 600
2050-01-01 00:30:00 2050-01-01 00:40:00 2050-01-01 00:30:00 2050-01-01 00:39:59 600
2050-01-01 00:40:00 2050-01-01 00:50:00 2050-01-01 00:40:00 2050-01-01 00:49:59 600
2050-01-01 00:50:00 2050-01-01 01:00:00 2050-01-01 00:50:00 2050-01-01 00:59:59 600
2050-01-01 01:00:00 2050-01-01 01:10:00 2050-01-01 01:00:00 2050-01-01 01:09:59 600
2050-01-01 01:10:00 2050-01-01 01:20:00 2050-01-01 01:10:00 2050-01-01 01:19:59 600
2050-01-01 01:20:00 2050-01-01 01:30:00 2050-01-01 01:20:00 2050-01-01 01:29:59 600
2050-01-01 01:30:00 2050-01-01 01:40:00 2050-01-01 01:30:00 2050-01-01 01:39:59 600
2050-01-01 01:40:00 2050-01-01 01:50:00 2050-01-01 01:40:00 2050-01-01 01:49:59 600
2050-01-01 01:50:00 2050-01-01 02:00:00 2050-01-01 01:50:00 2050-01-01 01:59:59 600

12 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;23.7 이전 버전은 아래의 표현식으로 2번 예제의 집계를 수행할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749374899906&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 3
SELECT   TRUNC (c1, 'HH24') + NUMTODSINTERVAL ( FLOOR (TO_CHAR (c1, 'MI.SS') / 10)      * 10, 'MINUTE') AS start_dt
       , TRUNC (c1, 'HH24') + NUMTODSINTERVAL ((FLOOR (TO_CHAR (c1, 'MI.SS') / 10) + 1) * 10, 'MINUTE') AS end_dt
       , MIN (c1) AS min_dt, MAX (c1) AS max_dt, COUNT (*) AS cnt
    FROM t1
GROUP BY TRUNC (c1, 'HH24') + NUMTODSINTERVAL ( FLOOR (TO_CHAR (c1, 'MI.SS') / 10)      * 10, 'MINUTE')
       , TRUNC (c1, 'HH24') + NUMTODSINTERVAL ((FLOOR (TO_CHAR (c1, 'MI.SS') / 10) + 1) * 10, 'MINUTE');

START_DT            END_DT              MIN_DT              MAX_DT              CNT
------------------- ------------------- ------------------- ------------------- ---
2050-01-01 00:00:00 2050-01-01 00:10:00 2050-01-01 00:00:00 2050-01-01 00:09:59 600
2050-01-01 00:10:00 2050-01-01 00:20:00 2050-01-01 00:10:00 2050-01-01 00:19:59 600
2050-01-01 00:20:00 2050-01-01 00:30:00 2050-01-01 00:20:00 2050-01-01 00:29:59 600
2050-01-01 00:30:00 2050-01-01 00:40:00 2050-01-01 00:30:00 2050-01-01 00:39:59 600
2050-01-01 00:40:00 2050-01-01 00:50:00 2050-01-01 00:40:00 2050-01-01 00:49:59 600
2050-01-01 00:50:00 2050-01-01 01:00:00 2050-01-01 00:50:00 2050-01-01 00:59:59 600
2050-01-01 01:00:00 2050-01-01 01:10:00 2050-01-01 01:00:00 2050-01-01 01:09:59 600
2050-01-01 01:10:00 2050-01-01 01:20:00 2050-01-01 01:10:00 2050-01-01 01:19:59 600
2050-01-01 01:20:00 2050-01-01 01:30:00 2050-01-01 01:20:00 2050-01-01 01:29:59 600
2050-01-01 01:30:00 2050-01-01 01:40:00 2050-01-01 01:30:00 2050-01-01 01:39:59 600
2050-01-01 01:40:00 2050-01-01 01:50:00 2050-01-01 01:40:00 2050-01-01 01:49:59 600
2050-01-01 01:50:00 2050-01-01 02:00:00 2050-01-01 01:50:00 2050-01-01 01:59:59 600

12 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 원점이 0001-01-01이고 간격이 2달인 버킷으로 데이터를 집계한 결과를 보여줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749374915649&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 4
SELECT   TIME_BUCKET (c1, 'P2M', DATE '0001-01-01') AS dt
       , TIME_BUCKET (c1, 'P2M', DATE '0001-01-01', END) AS dt
       , MIN (c1) AS min_dt, MAX (c1) AS max_dt, COUNT (*) AS cnt
    FROM t2
GROUP BY TIME_BUCKET (c1, 'P2M', DATE '0001-01-01')
       , TIME_BUCKET (c1, 'P2M', DATE '0001-01-01', END);

DT                  DT                  MIN_DT              MAX_DT              CNT
------------------- ------------------- ------------------- ------------------- ---
2050-01-01 00:00:00 2050-03-01 00:00:00 2050-01-01 00:00:00 2050-02-28 00:00:00  59
2050-03-01 00:00:00 2050-05-01 00:00:00 2050-03-01 00:00:00 2050-04-30 00:00:00  61
2050-05-01 00:00:00 2050-07-01 00:00:00 2050-05-01 00:00:00 2050-06-30 00:00:00  61
2050-07-01 00:00:00 2050-09-01 00:00:00 2050-07-01 00:00:00 2050-08-31 00:00:00  62
2050-09-01 00:00:00 2050-11-01 00:00:00 2050-09-01 00:00:00 2050-10-31 00:00:00  61
2050-11-01 00:00:00 2051-01-01 00:00:00 2050-11-01 00:00:00 2050-12-31 00:00:00  61
2051-01-01 00:00:00 2051-03-01 00:00:00 2051-01-01 00:00:00 2051-02-28 00:00:00  59
2051-03-01 00:00:00 2051-05-01 00:00:00 2051-03-01 00:00:00 2051-04-30 00:00:00  61
2051-05-01 00:00:00 2051-07-01 00:00:00 2051-05-01 00:00:00 2051-06-30 00:00:00  61
2051-07-01 00:00:00 2051-09-01 00:00:00 2051-07-01 00:00:00 2051-08-31 00:00:00  62
2051-09-01 00:00:00 2051-11-01 00:00:00 2051-09-01 00:00:00 2051-10-31 00:00:00  61
2051-11-01 00:00:00 2052-01-01 00:00:00 2051-11-01 00:00:00 2051-12-31 00:00:00  61

12 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;23.7 이전 버전은 아래의 표현식으로 4번 예제의 집계를 수행할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749374938036&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 5
SELECT   TRUNC (c1, 'YYYY') + NUMTOYMINTERVAL ((CEIL (TO_CHAR (c1, 'MM') / 2) - 1) * 2, 'MONTH') AS start_dt
       , TRUNC (c1, 'YYYY') + NUMTOYMINTERVAL ( CEIL (TO_CHAR (c1, 'MM') / 2)      * 2, 'MONTH') AS end_dt
       , MIN (c1) AS min_dt, MAX (c1) AS max_dt, COUNT (*) AS cnt
    FROM t2
GROUP BY TRUNC (c1, 'YYYY') + NUMTOYMINTERVAL ((CEIL (TO_CHAR (c1, 'MM') / 2) - 1) * 2, 'MONTH')
       , TRUNC (c1, 'YYYY') + NUMTOYMINTERVAL ( CEIL (TO_CHAR (c1, 'MM') / 2)      * 2, 'MONTH');

START_DT            END_DT              MIN_DT              MAX_DT              CNT
------------------- ------------------- ------------------- ------------------- ---
2050-01-01 00:00:00 2050-03-01 00:00:00 2050-01-01 00:00:00 2050-02-28 00:00:00  59
2050-03-01 00:00:00 2050-05-01 00:00:00 2050-03-01 00:00:00 2050-04-30 00:00:00  61
2050-05-01 00:00:00 2050-07-01 00:00:00 2050-05-01 00:00:00 2050-06-30 00:00:00  61
2050-07-01 00:00:00 2050-09-01 00:00:00 2050-07-01 00:00:00 2050-08-31 00:00:00  62
2050-09-01 00:00:00 2050-11-01 00:00:00 2050-09-01 00:00:00 2050-10-31 00:00:00  61
2050-11-01 00:00:00 2051-01-01 00:00:00 2050-11-01 00:00:00 2050-12-31 00:00:00  61
2051-01-01 00:00:00 2051-03-01 00:00:00 2051-01-01 00:00:00 2051-02-28 00:00:00  59
2051-03-01 00:00:00 2051-05-01 00:00:00 2051-03-01 00:00:00 2051-04-30 00:00:00  61
2051-05-01 00:00:00 2051-07-01 00:00:00 2051-05-01 00:00:00 2051-06-30 00:00:00  61
2051-07-01 00:00:00 2051-09-01 00:00:00 2051-07-01 00:00:00 2051-08-31 00:00:00  62
2051-09-01 00:00:00 2051-11-01 00:00:00 2051-09-01 00:00:00 2051-10-31 00:00:00  61
2051-11-01 00:00:00 2052-01-01 00:00:00 2051-11-01 00:00:00 2051-12-31 00:00:00  61

12 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 다섯 번째 인수의 동작을 보여줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749439799046&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 6-1
SELECT   TIME_BUCKET (c1, 'P1M', DATE '0001-11-30') AS start_dt
       , MIN (c1) AS min_dt, MAX (c1) AS max_dt, COUNT (*) AS cnt
    FROM t2
   WHERE c1 &amp;lt; DATE '2051-01-01'
GROUP BY TIME_BUCKET (c1, 'P1M', DATE '0001-11-30');

START_DT            MIN_DT              MAX_DT              CNT
------------------- ------------------- ------------------- ---
2049-12-30 00:00:00 2050-01-01 00:00:00 2050-01-29 00:00:00  29
2050-01-30 00:00:00 2050-01-30 00:00:00 2050-02-27 00:00:00  29
2050-02-28 00:00:00 2050-02-28 00:00:00 2050-03-29 00:00:00  30
2050-03-30 00:00:00 2050-03-30 00:00:00 2050-04-29 00:00:00  31
2050-04-30 00:00:00 2050-04-30 00:00:00 2050-05-29 00:00:00  30
2050-05-30 00:00:00 2050-05-30 00:00:00 2050-06-29 00:00:00  31
2050-06-30 00:00:00 2050-06-30 00:00:00 2050-07-29 00:00:00  30
2050-07-30 00:00:00 2050-07-30 00:00:00 2050-08-29 00:00:00  31
2050-08-30 00:00:00 2050-08-30 00:00:00 2050-09-29 00:00:00  31
2050-09-30 00:00:00 2050-09-30 00:00:00 2050-10-29 00:00:00  30
2050-10-30 00:00:00 2050-10-30 00:00:00 2050-11-29 00:00:00  31
2050-11-30 00:00:00 2050-11-30 00:00:00 2050-12-29 00:00:00  30
2050-12-30 00:00:00 2050-12-30 00:00:00 2050-12-31 00:00:00   2

13 rows selected.

-- 6-2
SELECT   TIME_BUCKET (c1, 'P1M', DATE '0001-11-30' ON OVERFLOW ERROR) AS start_dt
       , MIN (c1) AS min_dt, MAX (c1) AS max_dt, COUNT (*) AS cnt
    FROM t2
   WHERE c1 &amp;lt; DATE '2051-01-01'
GROUP BY TIME_BUCKET (c1, 'P1M', DATE '0001-11-30' ON OVERFLOW ERROR);

ORA-01839: date not valid for month specified

-- 6-3
SELECT   TIME_BUCKET (c1, 'P1M', DATE '0001-11-30' LAST DAY OF MONTH) AS start_dt
       , MIN (c1) AS min_dt, MAX (c1) AS max_dt, COUNT (*) AS cnt
    FROM t2
   WHERE c1 &amp;lt; DATE '2051-01-01'
GROUP BY TIME_BUCKET (c1, 'P1M', DATE '0001-11-30' LAST DAY OF MONTH);

START_DT            MIN_DT              MAX_DT              CNT
------------------- ------------------- ------------------- ---
2049-12-31 00:00:00 2050-01-01 00:00:00 2050-01-30 00:00:00  30
2050-01-31 00:00:00 2050-01-31 00:00:00 2050-02-27 00:00:00  28
2050-02-28 00:00:00 2050-02-28 00:00:00 2050-03-30 00:00:00  31
2050-03-31 00:00:00 2050-03-31 00:00:00 2050-04-29 00:00:00  30
2050-04-30 00:00:00 2050-04-30 00:00:00 2050-05-30 00:00:00  31
2050-05-31 00:00:00 2050-05-31 00:00:00 2050-06-29 00:00:00  30
2050-06-30 00:00:00 2050-06-30 00:00:00 2050-07-30 00:00:00  31
2050-07-31 00:00:00 2050-07-31 00:00:00 2050-08-30 00:00:00  31
2050-08-31 00:00:00 2050-08-31 00:00:00 2050-09-29 00:00:00  30
2050-09-30 00:00:00 2050-09-30 00:00:00 2050-10-30 00:00:00  31
2050-10-31 00:00:00 2050-10-31 00:00:00 2050-11-29 00:00:00  30
2050-11-30 00:00:00 2050-11-30 00:00:00 2050-12-30 00:00:00  31
2050-12-31 00:00:00 2050-12-31 00:00:00 2050-12-31 00:00:00   1

13 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;관련 링크&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/dwhsg/sql-analysis-reporting-data-warehouses.html#GUID-2CFE1687-078C-4728-AE2A-3795A3A86089&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TIME_BUCKET Function&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Oracle/SQL</category>
      <category>23ai</category>
      <author>정희락</author>
      <guid isPermaLink="true">https://tuna.tistory.com/209</guid>
      <comments>https://tuna.tistory.com/209#entry209comment</comments>
      <pubDate>Sun, 8 Jun 2025 18:29:06 +0900</pubDate>
    </item>
    <item>
      <title>Materialized Expression Columns</title>
      <link>https://tuna.tistory.com/208</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Oracle 23ai(23.7)에 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/nfcoa/ru_23_7.html#GUID-97377-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Materialized Expression Columns&lt;/a&gt; 기능이 추가되었습니다. Materialized Expression Column은 물리적으로 값이 저장되는 Virtual Column입니다. 기능이 추가되면서 Virtual Column을 Expression Column으로 명칭을 변경하고 기존의 Virtual Column을 Virtual Expression Column, 추가된 기능을 Materialized Expression Column으로 명명한 것으로 보입니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/CREATE-TABLE.html#GUID-F9CE0CC3-13AE-4744-A43C-EAC7A71AAAB6__BABIJABG&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;virtual_column_definition&lt;/a&gt; 절의 구문입니다. 칼럼 표현식 뒤에 VIRTUAL 또는 MATERIALIZED 키워드를 사용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749348133942&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;column [datatype] [ VISIBLE | INVISIBLE ] [GENERATED ALWAYS] AS (column_expression) [ VIRTUAL | MATERIALIZED ]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테스트를 위해 아래와 같이 테이블을 생성하겠습니다. c2 칼럼은 Virtual Expression Column, c3 칼럼은 Materialized Expression Column으로 생성됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749347704618&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1
DROP TABLE t1 PURGE;

CREATE TABLE t1 (
    c1 NUMBER
  , c2 NUMBER AS (c1 + 1)
  , c3 NUMBER AS (c1 + 2) MATERIALIZED
);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 *_TAB_COLS 뷰를 조회한 결과입니다. 현재까지 Materialized Expression Column을 구분할 수 있는 칼럼이 추가되지 않은 것으로 보입니다. data_default_vc IS NOT NULL AND virtual_column = 'NO' 조건으로 Materialized Expression Column을 식별할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749348592854&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 2
SELECT column_name, column_id, data_default_vc, virtual_column, segment_column_id
  FROM user_tab_cols
 WHERE table_name = 'T1';

COLUMN_NAM COLUMN_ID DATA_DEFAULT_VC VIRTUAL_COLUMN SEGMENT_COLUMN_ID
---------- --------- --------------- -------------- -----------------
C1                 1                 NO                             1
C2                 2 &quot;C1&quot;+1          YES
C3                 3 &quot;C1&quot;+2          NO                             2

3 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래와 같이 INSERT 문을 수행하겠습니다. Virtual Expression Column와 Materialized Expression Column 모두 데이터를 삽입할 수 없습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749347722883&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 3-1
INSERT INTO t1 (c1) VALUES (1);

1 row created.

INSERT INTO t1 (c2) VALUES (2);

ORA-54013: INSERT operation disallowed on virtual columns

INSERT INTO t1 (c3) VALUES (3);

ORA-54013: INSERT operation disallowed on virtual columns

COMMIT;

-- 3-2
SELECT * FROM t1;

C1 C2 C3
-- -- --
 1  2  3

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래는 블록 덤프 결과입니다. c1, c3 칼럼만 값이 저장된 것을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749347753031&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;block_row_dump:
tab 0, row 0, @0x1f8f
tl: 9 fb: --H-FL-- lb: 0x1  cc: 2
col  0: [ 2]  c1 02
col  1: [ 2]  c1 04
end_of_block_dump&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래와 같이 UPDATE 문을 수행하겠습니다. c2, c3 값이 변경된 것을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749347761850&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 3-1
UPDATE t1 SET c1 = 2;

-- 3-2
SELECT * FROM t1;

C1 C2 C3
-- -- --
 2  3  4

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Virtual Expression Column과 Materialized Expression Column 모두 인덱스를 생성할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749347784831&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 4-1
CREATE INDEX t1_x2 ON t1 (c2);

Index created.

-- 4-2
CREATE INDEX t1_x3 ON t1 (c3);

Index created.&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Oracle/Administration</category>
      <category>23ai</category>
      <author>정희락</author>
      <guid isPermaLink="true">https://tuna.tistory.com/208</guid>
      <comments>https://tuna.tistory.com/208#entry208comment</comments>
      <pubDate>Sun, 8 Jun 2025 11:14:35 +0900</pubDate>
    </item>
    <item>
      <title>Relational Data Vectorization</title>
      <link>https://tuna.tistory.com/207</link>
      <description>&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Oracle 23ai(23.6)에 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/26/vecse/october-2024-release-update-23.6.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Relational Data Vectorization&lt;/a&gt; 기능이 추가되었습니다. 이 기능을 사용하면 관계형 데이터로 벡터를 생성할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테스트를 위해 Bank Marketing&amp;nbsp;데이터를 &lt;a href=&quot;https://archive.ics.uci.edu/dataset/222/bank+marketing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;다운로드&lt;/a&gt;하여 아래와 같이 압축을 해제하겠습니다. bank-additional-full.csv 파일의 로우 수는 41,189 건입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749307870280&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ unzip bank+marketing.zip
$ unzip bank-additional.zip
$ cd bank-additional
$ wc -l bank-additional-full.csv
41189 bank-additional-full.csv&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래와 같이 External 테이블를 사용하여 bank-additional-full.csv 파일을 bank 테이블로 적재하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749307906265&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1-1
DROP DIRECTORY dir_bank;
CREATE DIRECTORY dir_bank AS '/home/oracle/bank/bank-additional';

-- 1-2
DROP TABLE ext_bank PURGE;

CREATE TABLE ext_bank (
    age            NUMBER
  , job            VARCHAR2(100)
  , marital        VARCHAR2(100)
  , education      VARCHAR2(100)
  , credit_default VARCHAR2(100)
  , housing        VARCHAR2(100)
  , loan           VARCHAR2(100)
  , contact        VARCHAR2(100)
  , month          VARCHAR2(100)
  , day_of_week    VARCHAR2(100)
  , duration       NUMBER
  , campaign       NUMBER
  , pdays          NUMBER
  , previous       NUMBER
  , poutcome       VARCHAR2(100)
  , emp_var_rate   NUMBER
  , cons_price_idx NUMBER
  , cons_conf_idx  NUMBER
  , euribor3m      NUMBER
  , nr_employed    NUMBER
  , y              VARCHAR2(100)
)
ORGANIZATION EXTERNAL (
    TYPE ORACLE_LOADER
    DEFAULT DIRECTORY dir_bank
    ACCESS PARAMETERS (
        RECORDS
        SKIP 1
        FIELDS CSV WITH EMBEDDED TERMINATED BY &quot;;&quot; OPTIONALLY ENCLOSED BY '&quot;'
        MISSING FIELD VALUES ARE NULL
    )
    LOCATION ('bank-additional-full.csv')
);

-- 1-3
DROP TABLE bank PURGE;

CREATE TABLE bank AS SELECT ROWNUM AS id, a.* FROM ext_bank a;

Elapsed: 00:00:00.27

-- 1-4
SELECT COUNT (*) AS cnt FROM bank;

  CNT
-----
41188

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래와 같이 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/26/arpls/DBMS_DATA_MINING.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DBMS_DATA_MINING&lt;/a&gt; 패키지를 사용해 모델을 생성하겠습니다. OML Feature Extraction은 데이터를 압축된 숫자 공간(벡터)에 투영합니다. 예제는 SVD 알고리즘을 구성하여 원본 데이터 테이블에 대해 Principal Component Analysis (PCA) 투영을 수행합니다. Feature 개수(칼럼 수와 벡터 수)는 5개입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749307953261&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 2-1
DECLARE
    v_setlist DBMS_DATA_MINING.SETTING_LIST;
BEGIN
    v_setlist(DBMS_DATA_MINING.ALGO_NAME)         := DBMS_DATA_MINING.ALGO_SINGULAR_VALUE_DECOMP;
    v_setlist(DBMS_DATA_MINING.PREP_AUTO)         := DBMS_DATA_MINING.PREP_AUTO_ON;
    v_setlist(DBMS_DATA_MINING.SVDS_SCORING_MODE) := DBMS_DATA_MINING.SVDS_SCORING_PCA;
    v_setlist(DBMS_DATA_MINING.FEAT_NUM_FEATURES) := '5';

    DBMS_DATA_MINING.DROP_MODEL (
        model_name =&amp;gt; 'BANK_MODEL'
      , force      =&amp;gt; TRUE
    );

    DBMS_DATA_MINING.CREATE_MODEL2 (
        model_name          =&amp;gt; 'BANK_MODEL'
      , mining_function     =&amp;gt; DBMS_DATA_MINING.FEATURE_EXTRACTION
      , data_query          =&amp;gt; 'SELECT * FROM BANK'
      , set_list            =&amp;gt; v_setlist
      , case_id_column_name =&amp;gt; 'ID'
    );
END;
/

-- 2-2
SELECT table_name, num_rows FROM user_tables WHERE table_name LIKE '%BANK_MODEL' ORDER BY table_name;

TABLE_NAME      NUM_ROWS
--------------- --------
DM$P5BANK_MODEL       68
DM$PABANK_MODEL        5
DM$PBBANK_MODEL      315
DM$PCBANK_MODEL        0
DM$PDBANK_MODEL       63
DM$PMBANK_MODEL       21
DM$PPBANK_MODEL        7

7 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래와 같이 벡터 테이블과 벡터 인덱스를 생성하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749308004120&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 3-1
SELECT id, VECTOR_EMBEDDING (bank_model USING *) AS embedding FROM bank WHERE id = 1;

ID EMBEDDING
-- --------------------------------------------------------------------------------------------------------------------------
 1 [-4.5287840901963311E-001,3.9973657855390535E+001,1.7814307848694632E+001,1.6308564650063971E+001,2.9979559766641883E+000]

1 row selected.

-- 3-2
DROP TABLE bank_vector PURGE;

CREATE TABLE bank_vector AS SELECT id, VECTOR_EMBEDDING (bank_model USING *) AS vector FROM bank;

-- 3-3
CREATE VECTOR INDEX bank_vector_x1 ON bank_vector (vector) ORGANIZATION NEIGHBOR PARTITIONS;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 id 1번 로우와 유사한 로우를 검색합니다. id 1번 로우의 Feature 칼럼은 cons_conf_idx, pdays, euribor3m, contact, campaign입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749308066977&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 4-1
SELECT FEATURE_DETAILS (bank_model, 5 USING *) AS features FROM bank WHERE id = 1;

FEATURES
----------------------------------------------------------------------------
&amp;lt;Details algorithm=&quot;Singular Value Decomposition&quot; feature=&quot;5&quot;&amp;gt;
&amp;lt;Attribute name=&quot;CONS_CONF_IDX&quot; actualValue=&quot;-36.4&quot; weight=&quot;.697&quot; rank=&quot;1&quot;/&amp;gt;
&amp;lt;Attribute name=&quot;PDAYS&quot; actualValue=&quot;999&quot; weight=&quot;.023&quot; rank=&quot;2&quot;/&amp;gt;
&amp;lt;Attribute name=&quot;EURIBOR3M&quot; actualValue=&quot;4.857&quot; weight=&quot;.014&quot; rank=&quot;3&quot;/&amp;gt;
&amp;lt;Attribute name=&quot;CONTACT&quot; actualValue=&quot;telephone&quot; weight=&quot;.009&quot; rank=&quot;4&quot;/&amp;gt;
&amp;lt;Attribute name=&quot;CAMPAIGN&quot; actualValue=&quot;1&quot; weight=&quot;.008&quot; rank=&quot;5&quot;/&amp;gt;
&amp;lt;/Details&amp;gt;

1 row selected.

-- 4-2
VAR b_vector CLOB

EXEC SELECT vector INTO :b_vector FROM bank_vector WHERE id = 1;

SELECT   a.id, b.age, b.marital, b.education, b.credit_default, b.housing
       , b.cons_conf_idx, b.pdays, b.euribor3m, b.contact, b.campaign
    FROM bank_vector a, bank b
   WHERE a.id != 1
     AND b.id = a.id
ORDER BY VECTOR_DISTANCE (a.vector, TO_VECTOR (:b_vector, 5, FLOAT64))
   FETCH FIRST 3 ROWS ONLY;

  ID AGE MARITAL EDUCATION  CREDIT_DEFAULT HOUSING CONS_CONF_IDX PDAYS EURIBOR3M CONTACT   CAMPAIGN
---- --- ------- ---------- -------------- ------- ------------- ----- --------- --------- --------
3631  56 married basic.9y   unknown        yes             -36.4   999     4.859 telephone        1
  22  55 married basic.4y   unknown        yes             -36.4   999     4.857 telephone        1
 459  54 married basic.4y   no             no              -36.4   999     4.857 telephone        2

3 rows selected.

-- 4-3
SELECT MIN (cons_conf_idx) AS min, MAX (cons_conf_idx) AS max, AVG (cons_conf_idx) AS avg, STDDEV (cons_conf_idx) AS std FROM bank;

    MIN    MAX    AVG  STD
 ------ ------ ------ ----
 -50.80 -26.90 -40.50 4.63

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 id 10000번 로우와 유사한 로우를 검색합니다. id 10000번 로우의 Feature 칼럼은 pdays, euribor3m, contact, emp_var_rate, day_of_week입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749308132326&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 5-1
SELECT FEATURE_DETAILS (bank_model, 5 USING *) AS features FROM bank WHERE id = 10000;

FEATURES
--------------------------------------------------------------------------
&amp;lt;Details algorithm=&quot;Singular Value Decomposition&quot; feature=&quot;5&quot;&amp;gt;
&amp;lt;Attribute name=&quot;PDAYS&quot; actualValue=&quot;999&quot; weight=&quot;.041&quot; rank=&quot;1&quot;/&amp;gt;
&amp;lt;Attribute name=&quot;EURIBOR3M&quot; actualValue=&quot;4.959&quot; weight=&quot;.028&quot; rank=&quot;2&quot;/&amp;gt;
&amp;lt;Attribute name=&quot;CONTACT&quot; actualValue=&quot;telephone&quot; weight=&quot;.016&quot; rank=&quot;3&quot;/&amp;gt;
&amp;lt;Attribute name=&quot;EMP_VAR_RATE&quot; actualValue=&quot;1.4&quot; weight=&quot;.014&quot; rank=&quot;4&quot;/&amp;gt;
&amp;lt;Attribute name=&quot;DAY_OF_WEEK&quot; actualValue=&quot;wed&quot; weight=&quot;.002&quot; rank=&quot;5&quot;/&amp;gt;
&amp;lt;/Details&amp;gt;

1 row selected.

-- 5-2
VAR b_vector CLOB

EXEC SELECT vector INTO :b_vector FROM bank_vector WHERE id = 10000;

SELECT   a.id, b.age, b.marital, b.education, b.credit_default, b.housing
       , b.pdays, b.euribor3m, b.contact, b.emp_var_rate, b.day_of_week
    FROM bank_vector a, bank b
   WHERE a.id != 10000
     AND b.id = a.id
ORDER BY VECTOR_DISTANCE (a.vector, TO_VECTOR (:b_vector, 5, FLOAT64))
   FETCH FIRST 3 ROWS ONLY;

   ID AGE MARITAL EDUCATION         CREDIT_DEFAULT HOUSING PDAYS  EURIBOR3M CONTACT   EMP_VAR_RATE DAY_OF_WEEK
----- --- ------- ----------------- -------------- ------- ----- ---------- --------- ------------ -----------
 9416  40 married basic.9y          no             no        999      4.967 telephone          1.4 fri
13485  40 married basic.4y          unknown        no        999      4.963 telephone          1.4 thu
 9800  40 single  university.degree no             yes       999      4.959 telephone          1.4 wed

3 rows selected.

-- 5-3
SELECT MIN (pdays) AS min, MAX (pdays) AS max, AVG (pdays) AS avg, STDDEV (pdays) AS std FROM bank;

 MIN   MAX     AVG    STD
---- ------ ------ ------
0.00 999.00 962.48 186.91

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;관련 링크&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/26/vecse/vectorize-relational-tables-using-oml-feature-extraction-algorithms.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Vectorize Relational Tables Using OML Feature Extraction Algorithms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/machine-learning/oml4sql/23/dmcon/feature-extraction.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Feature Extraction&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Oracle/Vector</category>
      <category>23ai</category>
      <author>정희락</author>
      <guid isPermaLink="true">https://tuna.tistory.com/207</guid>
      <comments>https://tuna.tistory.com/207#entry207comment</comments>
      <pubDate>Sat, 7 Jun 2025 23:55:42 +0900</pubDate>
    </item>
    <item>
      <title>Dynamic Statistics for PL/SQL Functions</title>
      <link>https://tuna.tistory.com/206</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;Oracle 23ai(23.8)에 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/nfcoa/ru_23_8.html#GUID-87016-13&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Dynamic Statistics for PL/SQL Functions&lt;/a&gt; 기능이 추가되었습니다. 이 기능은 PL/SQL 함수에 대한 동적 통계를 수집합니다. 이 글에서는 스칼라 타입을 반환하는 PL/SQL 함수를 스칼라 함수, 컬렉션 타입을 반환하는 PL/SQL 함수를 테이블 함수로 지칭합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/refrn/PLSQL_FUNCTION_DYNAMIC_STATS.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;plsql_function_dynamic_stats&lt;/a&gt; 파라미터로 PL/SQL 함수에 대한 동적 통계 수집의 동작을 설정할 수 있습니다. 기본값은 PREFERENCE로 dynamic_stats 설정에 따라 동적 통계를 수집합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749198312169&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1-1
SELECT name, value, isses_modifiable, issys_modifiable
  FROM v$parameter
 WHERE name = 'plsql_function_dynamic_stats';

NAME                         VALUE      ISSES_MODIFIABLE ISSYS_MODIFIABLE
---------------------------- ---------- ---------------- ----------------
plsql_function_dynamic_stats PREFERENCE TRUE             FALSE

1 row selected.

-- 1-2
SELECT ordinal, value, isdefault
  FROM v$parameter_valid_values
 WHERE name = 'plsql_function_dynamic_stats';

ORDINAL VALUE      ISDEFAULT
------- ---------- ---------
      1 CHOOSE     FALSE     -- 옵티마이저가 동적 통계의 수집 여부를 선택 (현재는 스칼라 함수에 대해서만 동적 통계를 수집)
      2 PREFERENCE TRUE      -- dynamic_stats 설정에 따라 동적 통계를 수집 (기본값)
      3 OFF        FALSE     -- 모든 함수에 대한 동적 통계의 수집를 비활성화
      4 ON         FALSE     -- 모든 함수에 대한 동적 통계의 수집를 활성화

4 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/DBMS_STATS.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DBMS_STATS&lt;/a&gt; 패키지에 PL/SQL 함수에 대한 동적 통계 수집과 관련된 서브프로그램이 추가되었습니다. SET_GLOBAL_PLSQL_PREFS 프로시저로 전역 수준의 dynamic_stats, SET_PLSQL_PREFS 프로시저로 함수 수준의 dynamic_stats를 설정할 수 있습니다. 전역 수준의 dynamic_stats의 기본값은 CHOOSE로 옵티마이저가 동적 통계의 수집 여부를 선택합니다. 현재는 스칼라 함수에 대한 동적 통계만 수집합니다. PL/SQL 함수에 대한 동적 통계의 수집 여부는 plsql_function_dynamic_stats 파라미터, 함수 수준의 dynamic_stats, 전역 수준의 dynamic_stats의 우선 순위로 결정됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749205106177&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 2-1
DBMS_STATS.SET_GLOBAL_PLSQL_PREFS (
    pname  IN VARCHAR2 -- dynamic_stats
  , pvalue IN VARCHAR2 -- ON, OFF, CHOOSE, NULL
);

-- 2-2
DBMS_STATS.RESET_GLOBAL_PLSQL_PREF_DEFAULTS

-- 2-3
DBMS_STATS.SET_PLSQL_PREFS (
    ownname        IN VARCHAR2
  , package_name   IN VARCHAR2
  , function_name  IN VARCHAR2
  , pname          IN VARCHAR2 -- dynamic_stats
  , pvalue         IN VARCHAR2 -- ON, OFF, CHOOSE, NULL
);

-- 2-4
DBMS_STATS.GET_PLSQL_PREFS (
    pname         IN VARCHAR2
  , ownname       IN VARCHAR2 DEFAULT NULL
  , package_name  IN VARCHAR2 DEFAULT NULL
  , function_name IN VARCHAR2 DEFAULT NULL
)
    RETURN VARCHAR2;

-- 2-5
DBMS_STATS.DELETE_PLSQL_PREFS (
    ownname       IN VARCHAR2
  , package_name  IN VARCHAR2
  , function_name IN VARCHAR2
  , pname         IN VARCHAR2
);

-- 2-6
SELECT DBMS_STATS.GET_PLSQL_PREFS ('dynamic_stats') AS dynamic_stats;

DYNAMIC_STATS
-------------
CHOOSE

1 row selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;스칼라 함수&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;스칼라 함수의 동작을 테스트하기 위해 아래와 같이 테이블과 함수를 생성하겠습니다. 오브젝트 통계가 존재하면 스칼라 함수에 대한 동적 통계가 수집되지 않으므로 CTAS 문에 NO_GATHER_OPTIMIZER_STATISTICS 힌트를 사용해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749205169173&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 3-1
DROP TABLE t1 PURGE;

CREATE TABLE t1 (c1) AS
SELECT   /*+ NO_GATHER_OPTIMIZER_STATISTICS */
         b.*
    FROM XMLTABLE ('1 to 15' COLUMNS c1 NUMBER PATH '.') a
       , XMLTABLE ('1 to 15' COLUMNS c1 NUMBER PATH '.') b
   WHERE b.c1 &amp;gt;= a.c1;

-- 3-2
DROP FUNCTION f1;

CREATE OR REPLACE FUNCTION f1 (i_value IN NUMBER)
    RETURN NUMBER
IS
BEGIN
    RETURN i_value;
END;
/&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래와 같이 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/refrn/OPTIMIZER_DYNAMIC_SAMPLING.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;optimizer_dynamic_sampling&lt;/a&gt; 파라미터를 2, _optim_peek_user_binds 파라미터를 TRUE로 설정하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749256485001&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 4
ALTER SESSION SET optimizer_dynamic_sampling = 2;
ALTER SESSION SET &quot;_optim_peek_user_binds&quot; = TRUE;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 스칼라 함수에 대한 동적 통계가 수집된 실행 계획을 보여줍니다. 예상 로우 수와 실제 로우 수가 동일한 것을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749256565252&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 5-1
SELECT * FROM t1 WHERE c1 = f1 (15);

-----------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     15 |       4 |
|*  1 |  TABLE ACCESS FULL| T1   |      1 |     15 |     15 |       4 |
-----------------------------------------------------------------------

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

-- 5-2
VAR b1 NUMBER = 15

SELECT * FROM t1 WHERE c1 = f1 (:b1);

-----------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     15 |       4 |
|*  1 |  TABLE ACCESS FULL| T1   |      1 |     15 |     15 |       4 |
-----------------------------------------------------------------------

Peeked Binds (identified by position):
--------------------------------------
   1 - (NUMBER): 15

-- 5-3
SELECT * FROM t1 WHERE c1 = f1 (c1);

-----------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |    120 |       5 |
|*  1 |  TABLE ACCESS FULL| T1   |      1 |    120 |    120 |       5 |
-----------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;plsql_function_dynamic_stats 파라미터를 OFF로 설정하거나 0 레벨의 &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Comments.html#GUID-72207153-4785-45D6-B1AA-CDB78D685FD1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DYNAMIC_SAMPLING&lt;/a&gt; 힌트를 사용하면 스칼라 함수에 대한 동적 통계가 수집되지 않습니다. 6-3번 예제는 서브 쿼리가 Execute Call에서 실행되므로 함수에 대한 동적 통계가 수집되지 않습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749256607671&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 6-1
SELECT /*+ OPT_PARAM('PLSQL_FUNCTION_DYNAMIC_STATS' 'OFF') */ * FROM t1 WHERE c1 = f1 (15);

-----------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     15 |       4 |
|*  1 |  TABLE ACCESS FULL| T1   |      1 |      3 |     15 |       4 |
-----------------------------------------------------------------------

-- 6-2
SELECT /*+ DYNAMIC_SAMPLING(0) */ * FROM t1 WHERE c1 = f1 (15);

-----------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     15 |       4 |
|*  1 |  TABLE ACCESS FULL| T1   |      1 |      3 |     15 |       4 |
-----------------------------------------------------------------------

-- 6-3
SELECT * FROM t1 WHERE c1 = (SELECT f1 (15) FROM DUAL);

-----------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     15 |       4 |
|*  1 |  TABLE ACCESS FULL| T1   |      1 |      1 |     15 |       4 |
|   2 |   FAST DUAL       |      |      1 |      1 |      1 |       0 |
-----------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테스트를 위해 아래와 같이 t1 테이블의 오브젝트 통계를 수집하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749256670859&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 7
EXEC DBMS_STATS.GATHER_TABLE_STATS (NULL, 'T1', no_invalidate =&amp;gt; FALSE);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 스칼라 함수에 대한 동적 통계가 수집되지 않은 실행 계획을 보여줍니다. E-Rows가 8(= 120 / 15)이므로 스칼라 함수에 대한 동적 통계가 수집되지 않는 것을 알 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749268763151&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 8
SELECT * FROM t1 WHERE c1 = f1 (15);

-----------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     15 |       3 |
|*  1 |  TABLE ACCESS FULL| T1   |      1 |      8 |     15 |       3 |
-----------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;plsql_function_dynamic_stats 파라미터를 ON으로 설정하거나 2 레벨의 DYNAMIC_SAMPLING 힌트를 사용해도 스칼라 함수에 대한 동적 통계가 수집되지 않습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749268799997&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 9-1
SELECT /*+ OPT_PARAM('PLSQL_FUNCTION_DYNAMIC_STATS' 'ON') */ * FROM t1 WHERE c1 = f1 (15);

-----------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     15 |       3 |
|*  1 |  TABLE ACCESS FULL| T1   |      1 |      8 |     15 |       3 |
-----------------------------------------------------------------------

-- 9-2
SELECT /*+ DYNAMIC_SAMPLING(2) */ * FROM t1 WHERE c1 = f1 (15);

-----------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     15 |       3 |
|*  1 |  TABLE ACCESS FULL| T1   |      1 |      8 |     15 |       3 |
-----------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;11 레벨의 DYNAMIC_SAMPLING 힌트를 사용하면 스칼라 함수에 대한 동적 통계가 수집되는 것으로 보입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749268812170&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 10
SELECT /*+ DYNAMIC_SAMPLING(11) */ * FROM t1 WHERE c1 = f1 (15);

-----------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows | Buffers |
-----------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     15 |       3 |
|*  1 |  TABLE ACCESS FULL| T1   |      1 |     15 |     15 |       3 |
-----------------------------------------------------------------------

Note
-----
   - dynamic statistics used: dynamic sampling (level=AUTO)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;테이블 함수&lt;/h2&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테이블 함수에 대한 동적 통계를 테스트하기 위해 아래와 같이 함수를 생성하겠습니다. f2 함수는 테이블 함수, f3 함수는 파이프라인 테이블 함수입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749256755145&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 11-1
CREATE OR REPLACE TYPE tnt_number FORCE AS TABLE OF NUMBER;
/

-- 11-2
DROP FUNCTION f2;

CREATE OR REPLACE FUNCTION f2 (i_value IN NUMBER)
    RETURN tnt_number
IS
    v1 tnt_number := tnt_number ();
BEGIN
    FOR i IN 1 .. i_value LOOP
        v1.EXTEND;
        v1(v1.LAST) := i;
    END LOOP;

    RETURN v1;
END;
/

-- 11-3
DROP FUNCTION f3;

CREATE OR REPLACE FUNCTION f3 (i_value IN NUMBER)
    RETURN tnt_number PIPELINED
IS
BEGIN
    FOR i IN 1 .. i_value LOOP
        PIPE ROW (i);
    END LOOP;
END;
/&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테이블 함수에 대한 동적 통계를 수집하기 위해 함수 수준의 dynamic_stats를 ON으로 설정하겠습니다. &lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/refrn/ALL_PROCEDURES.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;*_PROCEDURES&lt;/a&gt; 뷰의 dynamic_sampling_on, dynamic_sampling_off, dynamic_sampling_choose 칼럼에서 dynamic_stats 설정을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749257205185&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 12-1
EXEC DBMS_STATS.SET_PLSQL_PREFS (NULL, NULL, 'F2', 'dynamic_stats', 'ON');
EXEC DBMS_STATS.SET_PLSQL_PREFS (NULL, NULL, 'F3', 'dynamic_stats', 'ON');

-- 12-2
SELECT object_name, dynamic_sampling_on, dynamic_sampling_off, dynamic_sampling_choose
  FROM user_procedures
 WHERE object_name IN ('F1', 'F2', 'F3');

OBJECT_NAME DYNAMIC_SAMPLING_ON DYNAMIC_SAMPLING_OFF DYNAMIC_SAMPLING_CHOOSE
----------- ------------------- -------------------- -----------------------
F1          NO                  NO                   NO
F2          YES                 NO                   NO
F3          YES                 NO                   NO

3 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 테이블 함수에 대한 동적 통계가 수집된 실행 계획을 보여줍니다. E-Rows가 A-Rows와 동일한 것을 볼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749257215985&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 13-1
SELECT * FROM f2 (100);

-----------------------------------------------------------------------------
| Id  | Operation                         | Name | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |      1 |        |    100 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| F2   |      1 |    100 |    100 |
-----------------------------------------------------------------------------

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

-- 13-2
VAR b1 NUMBER = 100

SELECT * FROM f2 (:b1);

-----------------------------------------------------------------------------
| Id  | Operation                         | Name | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |      1 |        |    100 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| F2   |      1 |    100 |    100 |
-----------------------------------------------------------------------------

Peeked Binds (identified by position):
--------------------------------------
   1 - (NUMBER): 100

-- 13-3
SELECT * FROM f3 (100);

-----------------------------------------------------------------------------
| Id  | Operation                         | Name | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |      1 |        |    100 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| F3   |      1 |    100 |    100 |
-----------------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;plsql_function_dynamic_stats 파라미터를 OFF로 설정하거나 0 레벨의 DYNAMIC_SAMPLING 힌트를 사용하면 테이블 함수에 대한 동적 통계가 수집되지 않습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749257227493&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 14-1
SELECT /*+ OPT_PARAM('PLSQL_FUNCTION_DYNAMIC_STATS' 'OFF') */ * FROM f2 (100);

-----------------------------------------------------------------------------
| Id  | Operation                         | Name | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |      1 |        |    100 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| F2   |      1 |   8168 |    100 |
-----------------------------------------------------------------------------

-- 14-2
SELECT /*+ DYNAMIC_SAMPLING(0) */ * FROM f2 (100);

-----------------------------------------------------------------------------
| Id  | Operation                         | Name | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |      1 |        |    100 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| F2   |      1 |   8168 |    100 |
-----------------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;테스트를 위해 f2, f3 함수에 대한 dynamic_stats 설정을 기본값으로 설정하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749257239250&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 15-1
EXEC DBMS_STATS.SET_PLSQL_PREFS (NULL, NULL, 'F2', 'dynamic_stats', NULL);
EXEC DBMS_STATS.SET_PLSQL_PREFS (NULL, NULL, 'F3', 'dynamic_stats', NULL);

-- 15-2
SELECT object_name, dynamic_sampling_on, dynamic_sampling_off, dynamic_sampling_choose
  FROM user_procedures
 WHERE object_name IN ('F1', 'F2', 'F3');

OBJECT_NAME DYNAMIC_SAMPLING_ON DYNAMIC_SAMPLING_OFF DYNAMIC_SAMPLING_CHOOSE
----------- ------------------- -------------------- -----------------------
F1          NO                  NO                   NO
F2          NO                  NO                   NO
F3          NO                  NO                   NO

3 rows selected.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아래 예제는 테이블 함수에 대한 동적 통계가 수집되지 않은 실행 계획을 보여줍니다. E-Rows가 8168(기본값)이므로 테이블 함수에 대한 동적 통계가 수집되지 않는 것을 알 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749257284551&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 16
SELECT * FROM f2 (100);

-----------------------------------------------------------------------------
| Id  | Operation                         | Name | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |      1 |        |    100 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| F2   |      1 |   8168 |    100 |
-----------------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;plsql_function_dynamic_stats 파라미터를 ON으로 설정하거나 2 레벨의 DYNAMIC_SAMPLING 힌트를 사용하면 함수에 대한 동적 통계가 수집됩니다. 참고로 23.8 이전 버전에서도 2 레벨의 DYNAMIC_SAMPLING 힌트를 사용하면 테이블 함수에 대한 동적 통계가 수집됩니다. (optimizer_dynamic_sampling 파라미터 설정이 아닌 DYNAMIC_SAMPLING 힌트를 사용해야 함)&lt;/p&gt;
&lt;pre id=&quot;code_1749268924855&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 17-1
SELECT /*+ OPT_PARAM('PLSQL_FUNCTION_DYNAMIC_STATS' 'ON') */ * FROM f2 (100);

-----------------------------------------------------------------------------
| Id  | Operation                         | Name | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |      1 |        |    100 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| F2   |      1 |    100 |    100 |
-----------------------------------------------------------------------------

-- 17-2
SELECT  /*+ DYNAMIC_SAMPLING(2) */ * FROM f2 (100);

-----------------------------------------------------------------------------
| Id  | Operation                         | Name | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |      1 |        |    100 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| F2   |      1 |    100 |    100 |
-----------------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;아울러 23.8 이전 버전에서 6708183 Fix Control을 활성화해도 테이블 함수에 대한 동적 통계가 수집됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749268937518&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 18-1
SELECT bugno, value, sql_feature, description, optimizer_feature_enable
  FROM v$system_fix_control
 WHERE bugno = 6708183;

  BUGNO VALUE SQL_FEATURE                    DESCRIPTION                               OPTIMIZER_FEATURE_ENABLE
------- ----- ------------------------------ ----------------------------------------- ------------------------
6708183     0 QKSFM_DYNAMIC_SAMPLING_6708183 allow dynamic sampling on table functions

1 row selected.

-- 18-2
SELECT /*+ OPT_PARAM('_fix_control' '6708183:1') */ * FROM f2 (100);

-----------------------------------------------------------------------------
| Id  | Operation                         | Name | Starts | E-Rows | A-Rows |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |      |      1 |        |    100 |
|   1 |  COLLECTION ITERATOR PICKLER FETCH| F2   |      1 |    100 |    100 |
-----------------------------------------------------------------------------&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: justify;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;관련 링크&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/en/database/oracle/oracle-database/23/tgsql/options-for-optimizer-statistics-gathering.html#GUID-2E8DB339-B2A8-4706-AF84-712B49A5A5D1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;SQL Tuning Guide - Dynamic Statistics for PL/SQL Functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blogs.oracle.com/optimizer/post/plsql-ds&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Oracle Blog - Dynamic Statistics for PL/SQL Functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Oracle/Performance</category>
      <category>23ai</category>
      <author>정희락</author>
      <guid isPermaLink="true">https://tuna.tistory.com/206</guid>
      <comments>https://tuna.tistory.com/206#entry206comment</comments>
      <pubDate>Fri, 6 Jun 2025 17:25:18 +0900</pubDate>
    </item>
  </channel>
</rss>