EXPLAIN
EXPLAIN
The EXPLAIN command shows the query execution plan that Stoolap will use to execute a query. EXPLAIN ANALYZE additionally shows actual runtime statistics after executing the query.
Basic Syntax
-- Show planned execution strategy
EXPLAIN query;
-- Show plan with actual runtime statistics
EXPLAIN ANALYZE query;
EXPLAIN
Shows the execution plan without running the query.
Sequential Scan
When no suitable index exists:
EXPLAIN SELECT * FROM users;
Output:
plan
----
SELECT
Columns: *
-> Seq Scan on users
Primary Key Lookup
When filtering by primary key:
EXPLAIN SELECT * FROM users WHERE id = 1;
Output:
plan
----
SELECT
Columns: *
-> PK Lookup on users
id = 1
Index Scan
When using an index for equality:
CREATE INDEX idx_category ON products(category);
EXPLAIN SELECT * FROM products WHERE category = 'Electronics';
Output:
plan
----
SELECT
Columns: *
-> Index Scan using idx_category on products
Index Cond: category = Electronics
Index Range Scan
When using an index for range queries:
CREATE INDEX idx_value ON products(value);
EXPLAIN SELECT * FROM products WHERE value > 100;
Output:
plan
----
SELECT
Columns: *
-> Index Scan using idx_value on products
Index Cond: value > 100
Hash Join
When joining tables:
EXPLAIN SELECT o.id, c.name
FROM orders o
JOIN customers c ON o.customer_id = c.id;
Output:
plan
----
SELECT
Columns: o.id, c.name
-> Hash Join (INNER Join) (cost=1.10 rows=1)
Join Cond: (o.customer_id = c.id)
-> Seq Scan on orders
Alias: o
-> Seq Scan on customers
Alias: c
Aggregation
When using GROUP BY:
EXPLAIN SELECT category, SUM(value) FROM products GROUP BY category;
Output:
plan
----
SELECT
Columns: category, SUM(value)
-> Seq Scan on products
Group By: category
Sorting
When using ORDER BY:
EXPLAIN SELECT * FROM products ORDER BY value DESC;
Output:
plan
----
SELECT
Columns: *
-> Seq Scan on products
Order By: value DESC
EXPLAIN ANALYZE
Executes the query and shows actual runtime statistics.
EXPLAIN ANALYZE SELECT * FROM products WHERE value > 15;
Output:
plan
----
SELECT (actual time=1.53ms, rows=2)
Columns: *
-> Seq Scan on products (actual rows=2)
Filter: (value > 15)
Understanding EXPLAIN ANALYZE Output
| Field | Description |
|---|---|
| actual time | Total execution time |
| rows | Number of rows returned |
| actual rows | Rows processed at each step |
| Filter | WHERE condition applied |
Comparing Estimated vs Actual
EXPLAIN ANALYZE helps identify inaccurate estimates:
EXPLAIN ANALYZE SELECT * FROM large_table WHERE rare_condition = true;
If estimated rows differs significantly from actual rows:
- Run
ANALYZE table_nameto update statistics - Consider adding an index for the condition
Plan Components
Access Methods
| Component | Description |
|---|---|
| Seq Scan | Full table scan (reads all rows) |
| PK Lookup | Direct access by primary key |
| Index Scan | Uses index to find rows |
| Index Cond | Condition pushed to index |
| Filter | Condition applied after scan |
Join Methods
| Component | Description |
|---|---|
| Hash Join | Builds hash table, probes with other table |
| Merge Join | Joins sorted inputs |
| Nested Loop | Loops over each row combination |
| Join Cond | Join condition |
Modifiers
| Component | Description |
|---|---|
| Group By | Columns for aggregation |
| Order By | Sort specification |
| Limit | Row count limit |
| Alias | Table alias in query |
Cost Information
EXPLAIN shows cost estimates for joins:
-> Hash Join (INNER Join) (cost=1.10 rows=1)
- cost: Estimated total cost (relative units)
- rows: Estimated number of rows
Lower cost generally means faster execution.
Use Cases
Query Optimization
Use EXPLAIN to understand query behavior:
-- Check if index is being used
EXPLAIN SELECT * FROM orders WHERE customer_id = 100;
-- If showing Seq Scan, consider adding an index
CREATE INDEX idx_customer ON orders(customer_id);
-- Verify index is now used
EXPLAIN SELECT * FROM orders WHERE customer_id = 100;
Performance Debugging
Use EXPLAIN ANALYZE to find slow operations:
-- Find where time is spent
EXPLAIN ANALYZE SELECT o.*, c.name
FROM orders o
JOIN customers c ON o.customer_id = c.id
WHERE o.amount > 1000;
Look for:
- Large “actual rows” values
- Operations taking significant time
- Mismatch between estimated and actual rows
Index Effectiveness
Compare plans with and without indexes:
-- Without index
EXPLAIN ANALYZE SELECT * FROM products WHERE category = 'Electronics';
-- Add index
CREATE INDEX idx_category ON products(category);
-- With index
EXPLAIN ANALYZE SELECT * FROM products WHERE category = 'Electronics';
Best Practices
- Use EXPLAIN first: Check plan before running expensive queries
- Use EXPLAIN ANALYZE for optimization: Get actual numbers for tuning
- Check for Seq Scan on large tables: Consider adding indexes
- Verify index usage: Ensure expected indexes are being used
- Update statistics: Run ANALYZE after significant data changes
Limitations
- EXPLAIN shows the planned execution, not necessarily the exact runtime behavior
- Cost values are relative, not absolute time measurements
- Some runtime optimizations may not appear in the plan