Skip to content

Fix Ignite 3.1 SQL Join query performance issue (Step-by-Step Guide)

In Apache Ignite 3.1, SQL Join query performance issues typically manifest as high latency, excessive CPU utilization on specific nodes, or OutOfMemoryError during large result set processing. Unlike Ignite 2.x, Ignite 3 utilizes a high-performance Calcite-based SQL engine. When a Join query performs poorly, it usually indicates that the optimizer is failing to find an efficient execution path, resulting in a Broadcast Join (sending the entire table to all nodes) or a massive Data Shuffle (re-partitioning data across the cluster at runtime).

The following table outlines the most common technical triggers for degraded Join performance in Ignite 3.1:

Cause Explanation
Non-Colocated Joins Join keys do not match the Colocation Keys defined in the table schema, forcing data movement across the network.
Stale Statistics The Cost-Based Optimizer (CBO) lacks updated information on row counts and distribution, leading to suboptimal plan selection.
Index Scans vs. Table Scans Lack of secondary indexes on join predicates forces the engine into a nested loop join with full table scans.
Implicit Type Casting Joining columns with different data types (e.g., INT vs BIGINT) prevents the optimizer from utilizing indexes.
Memory Pressure Insufficient memory allocated to the SQL execution engine causes disk spilling or GC thrashing.

Before making changes, identify if the engine is performing a MAPREDUCE operation or a heavy SHUFFLE. Use the EXPLAIN keyword to inspect the plan.

EXPLAIN PLAN FOR
SELECT e.name, d.department_name
FROM Employee e
JOIN Department d ON e.dept_id = d.id;

Look for IgniteExchange or IgniteSortMergeJoin in the output. If you see high cost values or unexpected broadcasts, proceed to the next steps.

In Ignite 3, colocation is the primary way to ensure Joins happen locally on the same node. Ensure that the joining keys are defined as the COLOCATE BY keys during table creation.

-- Table 1: Primary key and colocation key is 'id'
CREATE TABLE Department (
id INT,
department_name VARCHAR,
PRIMARY KEY (id)
) COLOCATE BY (id);
-- Table 2: Use 'dept_id' as colocation key to match Department.id
CREATE TABLE Employee (
id INT,
dept_id INT,
name VARCHAR,
PRIMARY KEY (id, dept_id)
) COLOCATE BY (dept_id);

The Calcite engine relies on metadata to decide between Hash Join and Nested Loop. If statistics are missing, it defaults to heuristics which may be incorrect. Run the ANALYZE command.

Terminal window
# Execute via Ignite CLI or SQL tool
ANALYZE Department;
ANALYZE Employee;

For non-equijoins or complex predicates, ensure that the columns used in the ON and WHERE clauses are indexed to avoid TableScan.

CREATE INDEX idx_employee_dept ON Employee (dept_id);

Verify that the data types of the joined columns are identical. If Employee.dept_id is a BIGINT and Department.id is an INT, the index will be ignored.

-- Bad: Implicit cast
SELECT * FROM TableA a JOIN TableB b ON a.int_col = b.bigint_col;
-- Good: Exact matches
ALTER TABLE TableA ALTER COLUMN int_col SET DATA TYPE BIGINT;

To maintain high SQL performance in Ignite 3.1, integrate these practices into your development lifecycle:

  1. Define Colocation Early: Design your schema around Join patterns. Changing colocation keys later requires table recreation and data migration.
  2. Monitor Distribution Zones: Use Ignite 3 Distribution Zones to ensure that related tables are stored across the same set of data nodes.
  3. Automate ANALYZE: Schedule a task to run ANALYZE after significant data ingestion to keep the Cost-Based Optimizer accurate.
  4. Use SQL Benchmarking: Before deploying complex Joins to production, use the Ignite CLI to measure execution time with representative data volumes.
  5. Limit Result Sets: Always use LIMIT or FETCH FIRST for analytical queries to prevent the SQL engine from saturating the heap during the merge phase.

Press Ctrl + C in your CLI if you need to terminate a runaway long-running query before it impacts cluster stability.