SQL20 min readBy Priyanshu Pandey

SQL Architecture: CTEs vs. Global Temporary Tables (GTTs)

A comprehensive guide on when to use Common Table Expressions (CTEs/WITH clause), Global Temporary Tables (GTTs), and Private Temporary Tables in Oracle SQL. Understand memory overhead, undo/redo generation, and performance implications.

Architecture · SQL Mastery Series

SQL Architecture: CTEs vs. GTTs The Definitive Guide

When processing massive intermediate datasets, should you use an inline WITH clause (CTE) or persist the data into a Global Temporary Table (GTT)? Explore the architectural differences, memory implications, and performance trade-offs.

20 min read📅June 29, 2026✍️Priyanshu Pandey📚SQL Mastery Series
INTRODUCTION

1. The Need for Intermediate Storage

In complex analytical reporting or heavy batch processing (like Oracle RMS replenishment or stock ledger rollups), you rarely extract data in a single clean pass. You often need to:

  1. Aggregate a large baseline dataset.
  2. Filter it heavily.
  3. Join the intermediate result to several other massive tables.

How you store that intermediate dataset dictates the performance of your entire batch. The two dominant choices are Common Table Expressions (CTEs) and Global Temporary Tables (GTTs).

COMMON TABLE EXPRESSIONS

2. Common Table Expressions (WITH Clause)

CTEs allow you to define a subquery block at the beginning of your SQL statement.

Standard CTE Usage
SQL
WITH regional_sales AS (
    SELECT region_id, SUM(sales_amt) as total_sales
    FROM sales
    WHERE sales_date = TRUNC(SYSDATE)
    GROUP BY region_id
)
SELECT r.region_name, rs.total_sales
FROM regional_sales rs
JOIN regions r ON rs.region_id = r.region_id;

How the Optimizer Handles CTEs

The Oracle Optimizer has two choices when encountering a CTE:

  1. Inline it: It merges the CTE query directly into the main query block (as if it was just a subquery).
  2. Materialize it: It executes the CTE once, stores the result in a hidden temporary segment in the TEMP tablespace, and treats it like a table for the rest of the query.
ℹ️

The Materialize Hint

If you reference a CTE multiple times in the main query, the optimizer usually materializes it automatically. You can force this behavior using the /*+ MATERIALIZE */ hint inside the CTE definition.

Pros of CTEs:

  • Extremely clean, readable code.
  • Zero metadata overhead (no DDL required to create tables).
  • The optimizer has a global view of the entire query and can push predicates (filters) down into the CTE automatically.

Cons of CTEs:

  • Data only exists for the duration of the single SELECT statement.
  • You cannot index a CTE.
GLOBAL TEMPORARY TABLES

3. Global Temporary Tables (GTTs)

GTTs are persistent database objects (the table definition exists in the data dictionary permanently), but the data inside them is completely private to the session that inserted it.

Creating a GTT
SQL
CREATE GLOBAL TEMPORARY TABLE gtt_daily_sales (
    region_id NUMBER,
    total_sales NUMBER
) ON COMMIT PRESERVE ROWS; 
-- OR: ON COMMIT DELETE ROWS;

GTT Characteristics

  • Transaction or Session Scoped: ON COMMIT DELETE ROWS clears the table the moment you issue a COMMIT. PRESERVE ROWS keeps the data until you disconnect your session.
  • Indexable: You can create indexes on GTTs.
  • Undo/Redo Overhead: While GTTs do not generate redo for the data blocks, they do generate undo (for rollback capability), which in turn generates redo for the undo blocks. They are not "free" operations.

Pros of GTTs:

  • You can persist data across multiple separate PL/SQL steps.
  • You can add indexes to dramatically speed up subsequent joins.
  • You can gather statistics specifically on the GTT for complex execution plans.

Cons of GTTs:

  • Generates undo/redo overhead during inserts.
  • The definition is permanent, leading to a cluttered schema if abused.
PTTS

4. Private Temporary Tables (Oracle 18c+)

Introduced in Oracle 18c, Private Temporary Tables (PTTs) fix the primary complaint about GTTs: persistent metadata.

A PTT only exists in memory for the duration of a transaction or session. When the session ends, both the data and the table definition itself vanish.

Creating a Private Temporary Table
SQL
CREATE PRIVATE TEMPORARY TABLE ora$ptt_sales (
    region_id NUMBER,
    total_sales NUMBER
) ON COMMIT DROP DEFINITION;
💡

Naming Convention

PTTs must be prefixed with a specific initialization parameter, which defaults to ORA$PTT_.

DECISION MATRIX

5. When to use which?

ColumnTypeDescription
Scenario
Recommendation
Read-only query
CTE
Multi-step PL/SQL batch
GTT / PTT
Intermediate result needs indexing
GTT / PTT
Need to gather stats on intermediate result
GTT

Key Takeaways

    RetailCoder
    All systems operational
    v1.0 Live

    RC:OMS

    Multi-channel order management with double-entry inventory ledger. Amazon, Flipkart, Shopify, WooCommerce — one source of truth.

    Launch demo →
    v1.0 Live

    RC:Storefront

    Self-hosted headless e-commerce. Your server, your data, zero transaction fees. Native RC:OMS inventory sync.

    Visit Storefront →
    Pipeline

    RC:Pulse

    AI-powered retail analytics and demand forecasting — built natively on top of your RC:OMS and Storefront data.

    Request early access →
    Built in India 🇮🇳  ·  Architected by Priyanshu PandeyTalk to an engineer →