SQL Practice Logo

SQLPractice Online

Oracle: Advanced PL/SQL: Mistakes

Module: Database-Specific Features

Row-by-row processing with cursors instead of bulk operations

Use FORALL and BULK COLLECT for array processing

Cursors process rows one-by-one, causing context switches between PL/SQL and SQL engines. Each context switch costs 1-2ms. For 10,000 rows, that's 10-20 seconds just in context switches. Bulk operations process entire array in single operation (1 context switch).

Example - Cursor (SLOW):

BEGIN

FOR r IN (SELECT order_id FROM orders WHERE status = 'PENDING') LOOP

UPDATE orders SET status = 'PROCESSED' WHERE order_id = r.order_id;

END LOOP;

COMMIT;

END;

-- 10,000 rows: 30 seconds

-- CORRECT: Bulk operations (FAST)

DECLARE

TYPE t_order_ids IS TABLE OF NUMBER;

v_order_ids t_order_ids;

BEGIN

SELECT order_id BULK COLLECT INTO v_order_ids

FROM orders WHERE status = 'PENDING';

FORALL i IN 1..v_order_ids.COUNT

UPDATE orders SET status = 'PROCESSED' WHERE order_id = v_order_ids(i);

COMMIT;

END;

-- 10,000 rows: 0.3 seconds (100x faster)

Always use FORALL and BULK COLLECT for array processing. Use cursors only when you need to call external API per row or have complex per-row logic.

Critical

10-100x slower performance, 10,000 rows takes 30 seconds instead of 0.3 seconds

SQL injection in dynamic SQL by concatenating user input

Always use bind variables in EXECUTE IMMEDIATE

Concatenating user input directly into SQL string allows SQL injection attacks. Attackers can inject malicious SQL to access/modify unauthorized data.

Example - SQL Injection (DANGEROUS):

DECLARE

v_user_input VARCHAR2(100) := "100 OR 1=1"; -- Malicious input

v_sql VARCHAR2(1000);

v_count NUMBER;

BEGIN

v_sql := 'SELECT COUNT(*) FROM orders WHERE customer_id = ' || v_user_input;

EXECUTE IMMEDIATE v_sql INTO v_count;

-- Executes: SELECT COUNT(*) FROM orders WHERE customer_id = 100 OR 1=1

-- Returns all orders (security breach)

END;