Appearance
Generate UUID in Oracle
Oracle provides built-in UUID generation through the SYS_GUID()
function, which generates a 16-byte globally unique identifier:
sql
-- Generate UUID using SYS_GUID()
SELECT SYS_GUID() FROM DUAL;
-- Result: 550E8400E29B41D4A716446655440000 (32 hex characters)
-- Generate formatted UUID (with hyphens)
SELECT REGEXP_REPLACE(
RAWTOHEX(SYS_GUID()),
'([A-F0-9]{8})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{4})([A-F0-9]{12})',
'\1-\2-\3-\4-\5'
) AS formatted_uuid FROM DUAL;
-- Result: 550E8400-E29B-41D4-A716-446655440000
Oracle's SYS_GUID()
generates globally unique identifiers with the following characteristics:
sql
-- SYS_GUID() returns RAW(16) - 16 bytes of binary data
SELECT SYS_GUID() AS raw_uuid FROM DUAL;
-- Convert to hexadecimal string
SELECT RAWTOHEX(SYS_GUID()) AS hex_uuid FROM DUAL;
-- Convert to standard UUID format with hyphens
SELECT LOWER(REGEXP_REPLACE(
RAWTOHEX(SYS_GUID()),
'([a-f0-9]{8})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{12})',
'\1-\2-\3-\4-\5'
)) AS standard_uuid FROM DUAL;
-- Multiple UUIDs
SELECT SYS_GUID() AS uuid1, SYS_GUID() AS uuid2, SYS_GUID() AS uuid3 FROM DUAL;
Table Schema with UUID Primary Keys
Using RAW(16) for optimal storage:
sql
-- Create table with RAW UUID primary key
CREATE TABLE users (
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
name VARCHAR2(100) NOT NULL,
email VARCHAR2(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Insert data (UUID generated automatically)
INSERT INTO users (name, email)
VALUES ('John Doe', '[email protected]');
-- Query with UUID (using HEXTORAW for string input)
SELECT * FROM users
WHERE id = HEXTORAW('550E8400E29B41D4A716446655440000');
Using VARCHAR2 for human-readable UUIDs:
sql
-- Create table with formatted UUID
CREATE TABLE orders (
id VARCHAR2(36) DEFAULT LOWER(REGEXP_REPLACE(
RAWTOHEX(SYS_GUID()),
'([a-f0-9]{8})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{12})',
'\1-\2-\3-\4-\5'
)) PRIMARY KEY,
user_id RAW(16) NOT NULL,
order_number VARCHAR2(50),
total NUMBER(10,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id)
);
-- Create indexes
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_created_at ON orders(created_at);
Advanced Oracle UUID Usage
UUID utility functions:
sql
-- Create package for UUID utilities
CREATE OR REPLACE PACKAGE uuid_utils AS
FUNCTION generate_uuid RETURN VARCHAR2;
FUNCTION generate_raw_uuid RETURN RAW;
FUNCTION format_uuid(p_raw_uuid RAW) RETURN VARCHAR2;
FUNCTION parse_uuid(p_uuid_string VARCHAR2) RETURN RAW;
FUNCTION is_valid_uuid(p_uuid_string VARCHAR2) RETURN NUMBER;
END uuid_utils;
/
CREATE OR REPLACE PACKAGE BODY uuid_utils AS
FUNCTION generate_uuid RETURN VARCHAR2 IS
BEGIN
RETURN LOWER(REGEXP_REPLACE(
RAWTOHEX(SYS_GUID()),
'([a-f0-9]{8})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{12})',
'\1-\2-\3-\4-\5'
));
END generate_uuid;
FUNCTION generate_raw_uuid RETURN RAW IS
BEGIN
RETURN SYS_GUID();
END generate_raw_uuid;
FUNCTION format_uuid(p_raw_uuid RAW) RETURN VARCHAR2 IS
BEGIN
RETURN LOWER(REGEXP_REPLACE(
RAWTOHEX(p_raw_uuid),
'([a-f0-9]{8})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{4})([a-f0-9]{12})',
'\1-\2-\3-\4-\5'
));
END format_uuid;
FUNCTION parse_uuid(p_uuid_string VARCHAR2) RETURN RAW IS
BEGIN
RETURN HEXTORAW(REPLACE(UPPER(p_uuid_string), '-', ''));
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END parse_uuid;
FUNCTION is_valid_uuid(p_uuid_string VARCHAR2) RETURN NUMBER IS
BEGIN
IF REGEXP_LIKE(p_uuid_string, '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$') THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END is_valid_uuid;
END uuid_utils;
/
-- Usage examples
SELECT uuid_utils.generate_uuid() AS formatted_uuid FROM DUAL;
SELECT uuid_utils.generate_raw_uuid() AS raw_uuid FROM DUAL;
SELECT uuid_utils.is_valid_uuid('550e8400-e29b-41d4-a716-446655440000') AS is_valid FROM DUAL;
Triggers for UUID generation:
sql
-- Trigger to automatically generate UUIDs
CREATE OR REPLACE TRIGGER trg_users_uuid
BEFORE INSERT ON users
FOR EACH ROW
BEGIN
IF :NEW.id IS NULL THEN
:NEW.id := SYS_GUID();
END IF;
END;
/
-- Trigger with formatted UUID
CREATE OR REPLACE TRIGGER trg_orders_uuid
BEFORE INSERT ON orders
FOR EACH ROW
BEGIN
IF :NEW.id IS NULL THEN
:NEW.id := uuid_utils.generate_uuid();
END IF;
END;
/
Performance Optimization
Index strategies for UUID columns:
sql
-- B-tree index on RAW UUID (default)
CREATE INDEX idx_users_id ON users(id);
-- Function-based index for formatted lookups
CREATE INDEX idx_users_formatted_id ON users(uuid_utils.format_uuid(id));
-- Composite indexes with UUID
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
-- Reverse key index for better distribution (if needed)
CREATE INDEX idx_users_id_reverse ON users(id) REVERSE;
Partitioning with UUIDs:
sql
-- Hash partitioning with UUID
CREATE TABLE large_dataset (
id RAW(16) DEFAULT SYS_GUID(),
data CLOB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
PARTITION BY HASH(id) PARTITIONS 8;
-- Range partitioning by date (more common)
CREATE TABLE time_series_data (
id RAW(16) DEFAULT SYS_GUID(),
event_data CLOB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
PARTITION BY RANGE(created_at) (
PARTITION p2024_q1 VALUES LESS THAN (DATE '2024-04-01'),
PARTITION p2024_q2 VALUES LESS THAN (DATE '2024-07-01'),
PARTITION p2024_q3 VALUES LESS THAN (DATE '2024-10-01'),
PARTITION p2024_q4 VALUES LESS THAN (DATE '2025-01-01')
);
PL/SQL Integration
Stored procedures with UUIDs:
sql
-- Procedure to create user with UUID
CREATE OR REPLACE PROCEDURE create_user(
p_name IN VARCHAR2,
p_email IN VARCHAR2,
p_user_id OUT RAW
) AS
BEGIN
p_user_id := SYS_GUID();
INSERT INTO users (id, name, email)
VALUES (p_user_id, p_name, p_email);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
END create_user;
/
-- Function to get formatted UUID
CREATE OR REPLACE FUNCTION get_user_uuid(p_user_id RAW)
RETURN VARCHAR2 AS
BEGIN
RETURN uuid_utils.format_uuid(p_user_id);
END get_user_uuid;
/
-- Usage
DECLARE
v_user_id RAW(16);
v_formatted_id VARCHAR2(36);
BEGIN
create_user('Jane Doe', '[email protected]', v_user_id);
v_formatted_id := get_user_uuid(v_user_id);
DBMS_OUTPUT.PUT_LINE('Created user with UUID: ' || v_formatted_id);
END;
/
Bulk operations with UUIDs:
sql
-- Bulk insert with UUIDs
DECLARE
TYPE t_names IS TABLE OF VARCHAR2(100);
TYPE t_emails IS TABLE OF VARCHAR2(255);
TYPE t_ids IS TABLE OF RAW(16);
v_names t_names := t_names('User1', 'User2', 'User3', 'User4', 'User5');
v_emails t_emails := t_emails('[email protected]', '[email protected]',
'[email protected]', '[email protected]', '[email protected]');
v_ids t_ids := t_ids();
BEGIN
-- Generate UUIDs
v_ids.EXTEND(v_names.COUNT);
FOR i IN 1..v_names.COUNT LOOP
v_ids(i) := SYS_GUID();
END LOOP;
-- Bulk insert
FORALL i IN 1..v_names.COUNT
INSERT INTO users (id, name, email)
VALUES (v_ids(i), v_names(i), v_emails(i));
COMMIT;
-- Display generated UUIDs
FOR i IN 1..v_ids.COUNT LOOP
DBMS_OUTPUT.PUT_LINE('User ' || v_names(i) || ': ' || uuid_utils.format_uuid(v_ids(i)));
END LOOP;
END;
/
Oracle RAC and Distributed Systems
UUID considerations for Oracle RAC:
sql
-- UUIDs are perfect for Oracle RAC (no sequence conflicts)
CREATE TABLE rac_safe_table (
id RAW(16) DEFAULT SYS_GUID() PRIMARY KEY,
node_id NUMBER DEFAULT SYS_CONTEXT('USERENV', 'INSTANCE'),
data VARCHAR2(4000),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Query to see distribution across RAC nodes
SELECT node_id, COUNT(*) as record_count
FROM rac_safe_table
GROUP BY node_id
ORDER BY node_id;
Data Guard and replication:
sql
-- UUIDs work seamlessly with Data Guard
-- No special configuration needed for UUID columns
-- Materialized view with UUIDs
CREATE MATERIALIZED VIEW user_summary
REFRESH FAST ON COMMIT AS
SELECT
id,
uuid_utils.format_uuid(id) as formatted_id,
name,
email,
created_at
FROM users;
Migration and Data Import
Converting existing tables to UUID:
sql
-- Add UUID column to existing table
ALTER TABLE existing_table ADD (uuid_id RAW(16));
-- Update existing rows with UUIDs
UPDATE existing_table SET uuid_id = SYS_GUID() WHERE uuid_id IS NULL;
-- Make UUID column NOT NULL
ALTER TABLE existing_table MODIFY (uuid_id RAW(16) NOT NULL);
-- Add unique constraint
ALTER TABLE existing_table ADD CONSTRAINT uk_existing_table_uuid UNIQUE (uuid_id);
Data import with UUIDs:
sql
-- External table for CSV import with UUID generation
CREATE TABLE ext_users_csv (
name VARCHAR2(100),
email VARCHAR2(255)
)
ORGANIZATION EXTERNAL (
TYPE ORACLE_LOADER
DEFAULT DIRECTORY data_dir
ACCESS PARAMETERS (
RECORDS DELIMITED BY NEWLINE
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
)
LOCATION ('users.csv')
);
-- Import with UUID generation
INSERT INTO users (id, name, email)
SELECT SYS_GUID(), name, email
FROM ext_users_csv;
Monitoring and Performance
UUID-related performance queries:
sql
-- Check UUID column statistics
SELECT
column_name,
data_type,
data_length,
num_distinct,
density
FROM user_tab_col_statistics
WHERE table_name = 'USERS' AND column_name = 'ID';
-- Index usage for UUID columns
SELECT
i.index_name,
i.uniqueness,
ic.column_name,
ic.column_position
FROM user_indexes i
JOIN user_ind_columns ic ON i.index_name = ic.index_name
WHERE ic.table_name = 'USERS'
ORDER BY i.index_name, ic.column_position;
-- Query execution plans for UUID lookups
EXPLAIN PLAN FOR
SELECT * FROM users WHERE id = HEXTORAW('550E8400E29B41D4A716446655440000');
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
UUID Version Comparison
Choose the right approach for your Oracle application:
- SYS_GUID() - Oracle's native UUID generation (similar to Version 4)
- Version 1 - Time-based UUID (custom implementation needed)
- Version 3 - MD5 namespace-based (custom implementation)
- Version 5 - SHA-1 namespace-based (custom implementation)
For Oracle applications:
- Enterprise systems: Use SYS_GUID() for maximum compatibility
- Distributed systems: SYS_GUID() works excellently across Oracle RAC
- Data warehousing: Consider sequence-based keys for better performance
How do I generate UUID in other databases?
SQL databases:
- PostgreSQL - Comprehensive UUID support with extensions
- MySQL - Built-in UUID() function
- SQL Server - NEWID() and NEWSEQUENTIALID()
- SQLite - Custom functions and extensions
NoSQL databases: