Oracle Scratchpad

March 17, 2014

Temporary Segments

Filed under: Infrastructure,Oracle — Jonathan Lewis @ 6:25 pm GMT Mar 17,2014

A question came up on oracle-l recently about identifying which temporary segment in v$tempseg_usage is associated with which global temporary table (GTT). Here’s my answer:

v$tempseg_usage is a synonym for v$sort_usage – which is the view that I still tend to think of first – and v$sort_usage is a view over x$ktsso, and in x$ktsso the column ktssoobjn is the object number for the definition of the global temporary table (ditto for any indexes on the table). [Addendum: I didn’t point it out in the reply, but v$lock will show a TM lock with id1 set to the table object_id, and id2 set to zero, and two TO locks with the same value for id1, but with id2 set to 1 and 2 respectively.]

If an internal GTT has appeared because of subquery factoring (“with” subquery / CTE) this correspondance is a little broken but if you look in the execution plan (v$sql_plan / dbms_xplan.display_cursor()) for the query you will find lines like:

|  63 |    HASH JOIN                          |                            |
|  64 |     VIEW                              |                            |
|  65 |      TABLE ACCESS FULL                | SYS_TEMP_0FD9D667C_74A306D |
|  66 |     VIEW                              |                            |
|  67 |      TABLE ACCESS FULL                | SYS_TEMP_0FD9D667B_74A306D |

There will be corresponding TO locks in v$lock (note the negative value):

ADDR             KADDR                   SID TY        ID1        ID2
---------------- ---------------- ---------- -- ---------- ----------
000000008ED8EC68 000000008ED8ECC0        143 TO  -40016261          1
000000008ED8F540 000000008ED8F598        143 TO  -40016260          1

And there will be some large values for ktssoobjn in x$ktsso:

  KTSSOBNO  KTSSOEXTS  KTSSOBLKS  KTSSORFNO  KTSSOOBJD  KTSSOOBJN KTSSOTSNUM KTSSOSQLID
---------- ---------- ---------- ---------- ---------- ---------- ---------- -------------
     49792          1        128          1    4244096 4254951035          3 anb4mscz7wz71
     49152          1        128          1    4243456 4254951036          3 anb4mscz7wz71

Check the middle section of the SYS_TEMP name:

0x0FD9D667C = 4254951036

and then spot the arithmetic:

4254951036 + 40016260 = 4294967296 = 0x100000000 = power(2,32)

v$lock.id1 is a 16 bit wrap of x$ktsso.ktssoobjn, so add it to power(2,32) and you can look for it (for the relevant session) in x$ktsso.

For things like sorts we can check v$sql_workarea_active against v$sort_usage / v$tempseg_usage (though you might stick with x$ktsso to be consistent) since both hold the relative file and block number for the segment.

Follow-up

Shortly after posting a reply to the original question I received an email from Stefan Koehler pointing out that in 11.2.0.2 the object x$ktsso was enhanced to include the sql_id of the statement that caused a temporary object to come into existence. (If you check the definition of v$sort_usage/v$tempseg_usage you’ll see that the sql_id that it’s reporting is the prev_sql_id from V$session).  Stefan also gave me a link to a note that he had written on the topic.

It is an oddity of v$sort_usage / v$tempseg_usage that it holds a column called session num which suggests that it ought to be the SID: it isn’t, it’s the v$session.serial#. To connect to the session information it’s probably best to join the session_addr to v$session.saddr).

(Some time later): a little oddity that I tracked down by session_addr and session_num was that an idle M001 (shared MMON slave) session was holding a (small) temporary segment long after it had last executed the statement that had allocated it. The statement in question (with a little cosmetic editing) was:

INSERT INTO WRI$_ADV_ADDM_PDBS (CON_DBID, PDB_NAME) 
SELECT   CON_DBID, SUBSTR(X,20) 
FROM     ( 
         SELECT
                 I.CON_DBID, 
                 MAX(TO_CHAR(I.OPEN_TIME, 'YYYY:MM:DD HH24:MI:SS') || I.PDB_NAME) AS X 
        FROM
                AWR_PDB_PDB_INSTANCE I, 
                AWR_PDB_SNAPSHOT S 
        WHERE 
                S.DBID = :B1 
        AND     S.INSTANCE_NUMBER = I.INSTANCE_NUMBER 
        AND     S.SNAP_ID = :B3 
        AND     I.STARTUP_TIME >= S.STARTUP_TIME 
        AND     I.STARTUP_TIME <= :B2 
        AND     I.CON_DBID <> 0 
        AND     I.CON_DBID <> :B1 
        AND     I.DBID = :B1 
        AND     I.PDB_NAME IS NOT NULL 
        GROUP BY  
                I.CON_DBID 
        )

6 Comments »

  1. The SQL_ID issue is also mentioned in a comment in this article: https://jonathanlewis.wordpress.com/2014/02/16/recursive-subquery-factoring/

    Comment by jkstill — March 18, 2014 @ 2:13 am GMT Mar 18,2014 | Reply

  2. […] 12c the temporary undo segment is reported with segtype = “UNDEFINED” in v$sort_usage/v$tempseg_usage; by 19c this has changed to “TEMP […]

    Pingback by 12c Temporary | Oracle Scratchpad — February 26, 2021 @ 11:28 am GMT Feb 26,2021 | Reply

  3. Jonathan,

    This is only to point out that from now on (probably starting with version 11g) the missing information about the sql_id at the origin of the TEMP is visible via the column SQL_ID_TEMPSEG

    SQL> desc v$tempseg_usage 
     Name                     Null?    Type
     ------------------------ -------- ----------------------------
     USERNAME                          VARCHAR2(128)
     USER                              VARCHAR2(128)
     SESSION_ADDR                      RAW(8)
     SESSION_NUM                       NUMBER
     SQLADDR                           RAW(8)
     SQLHASH                           NUMBER
     SQL_ID                            VARCHAR2(13)
     TABLESPACE                        VARCHAR2(30)
     CONTENTS                          VARCHAR2(9)
     SEGTYPE                           VARCHAR2(9)
     SEGFILE#                          NUMBER
     SEGBLK#                           NUMBER
     EXTENTS                           NUMBER
     BLOCKS                            NUMBER
     SEGRFNO#                          NUMBER
     TS#                               NUMBER
     CON_ID                            NUMBER
     SQL_ID_TEMPSEG                    VARCHAR2(13)
    

    But, unfortunately, the sql_id column still (19.8) points to the LAST SQL statement executed by the session (SESSION_ADD, SESSION_NUM) which may be something that has nothing to do with the TEMP.

    Also, this week I was confronted with a TEMP explosion due to the usage of a TEMPORARY LOB by sessions coming from a JAVA connection pool that do not release the TEMPORAY LOB until they are disconnected. In this case, ASH shows no TEMP consumption because the java sessions filling the TEMPORARY LOB are Idle (sql net data from client). The TEMP overconsumption is only visible via gv$tempseg_usage view where the SQL_ID_TEMPSEG = 0000000000000. Not sure how to interpret this SQL_ID_TEMPSEG in this case.

    Best Regards
    Mohamed Houri

    Comment by hourim — September 28, 2021 @ 12:39 pm BST Sep 28,2021 | Reply

    • Mohamed,

      Thanks for the comment.

      It’s always used to accumulate corrections and extensions to the notes – especially when it’s comments about threats like your comment about temporary lobs and idle sessions in a connection pool. We always need to have alternative ways to find critical information.

      I’ve got dumps of the fixed view definitions from various old versions or Oracle, and though the relevant column appeared in the x$ by 11.2.0.4, I’ve just checked and found that it wasn’t exposed in the v$ in 11.2.0.4 and didn’t arrive there until 12.1.

      Regards
      Jonathan Lewis

      Comment by Jonathan Lewis — September 28, 2021 @ 1:06 pm BST Sep 28,2021 | Reply

    • Mohamed,

      I have seen quite a few databases lately where the application server pools contain huge number of connection, up to 400:1 session:core average.

      Just wondering if you think the number of connections is having an effect on this as well.

      Jared

      Comment by Jared — September 28, 2021 @ 5:13 pm BST Sep 28,2021 | Reply

  4. Jared,

    Regarding the TEMP consumption due to the creation of TEMPORARY LOBs, the number of connected sessions is only concerned if these sessions create TEMPORARY LOBs, use them, and return to the connection pool without being disconnected. As such, they keep their CACHE_LOBS and NOCACHE_LOBS active (values >0) in v$temporary_lobs even if they are Idle. If this session is re-used and creates a new temporary lob the existing temporary lob is not reused and a new one is created and so on. The session in the pool should explicitly free the temporary lob to avoid this situation. In one of my applications, while a call to a DBMS_LOB.FREETEMPORARY was enough to free the TEMP in 12c, it looks like this is not working as expected in 19c. I am still trying to figure this out.

    Best regards
    Mohamed Houri

    Comment by hourim — September 29, 2021 @ 8:43 am BST Sep 29,2021 | Reply


RSS feed for comments on this post. TrackBack URI

Comments and related questions are welcome.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Website Powered by WordPress.com.