Skip to main content
FiQueLa includes a built-in execution planner. Use EXPLAIN to see which pipeline stages will run and in what order, or use EXPLAIN ANALYZE to actually execute the query and capture real row counts, timings, and memory usage per stage.

Plan-only vs analysis mode

ModeRuns queryMetrics collected
EXPLAINNoAll metric columns are null
EXPLAIN ANALYZEYesRow counts, timings, memory per phase
Both modes return a flat table (stored in Results\InMemory) with the same eight columns.

Output columns

ColumnTypeDescription
phasestringPipeline stage name
rows_inint|nullRows entering the phase (null for plan-only)
rows_outint|nullRows leaving the phase (null for plan-only)
filteredint|nullRows removed (rows_in − rows_out; null for plan-only)
time_msfloat|nullWall-clock time in milliseconds (null for plan-only)
duration_pctfloat|nullPercentage of total query time (null for plan-only)
mem_peak_kbfloat|nullPeak memory in KB at the end of the phase (null for plan-only)
notestringHuman-readable description of the phase configuration

Pipeline stage names

PhaseDescription
streamReading rows from the source file
joinApplying join conditions against another data source
whereFiltering rows before aggregation
groupGrouping rows and computing aggregates
havingFiltering grouped results
sortSorting the result set
limitApplying LIMIT / OFFSET
unionMerging results from a union sub-query

Union sub-phases

When a query includes UNION or UNION ALL, each union branch reports its own sub-phases inside the explain output. Single union — phases are prefixed with union_:
union_stream → union_where → union (summary row)
Multiple unions — phases are indexed:
union_1_stream → union_1_where → union_1 (summary)
union_2_stream → union_2_where → union_2 (summary)

Usage

use FQL\Enum\Operator;
use FQL\Query\Provider;

// Plan only — no query execution
$results = Provider::fromFileQuery('json(./data/products.json).data.products')
    ->select('id', 'name')
    ->where('price', Operator::GREATER_THAN, 100)
    ->orderBy('name')
    ->limit(10)
    ->explain()
    ->execute();

foreach ($results->fetchAll() as $row) {
    print_r($row);
}
use FQL\Enum\Operator;
use FQL\Query\Provider;

// Execute the query and collect real metrics
$results = Provider::fromFileQuery('json(./data/products.json).data.products')
    ->select('id', 'name')
    ->where('price', Operator::GREATER_THAN, 100)
    ->orderBy('name')
    ->limit(10)
    ->explainAnalyze()
    ->execute();

foreach ($results->fetchAll() as $row) {
    print_r($row);
}

EXPLAIN ANALYZE with UNION

The example below produces phases: stream, where, limit, union_stream, union_where, union.
use FQL\Enum\Operator;
use FQL\Stream\Json;

$stream = Json::open('./data/products.json');

$query1 = $stream->query()
    ->select('id')
    ->from('data.products')
    ->where('price', Operator::GREATER_THAN, 100);

$query2 = $stream->query()
    ->select('id')
    ->from('data.products')
    ->where('price', Operator::GREATER_THAN, 200);

$results = $query1
    ->limit(5)
    ->unionAll($query2)
    ->explainAnalyze()
    ->execute();

foreach ($results->fetchAll() as $row) {
    print_r($row);
}
EXPLAIN and EXPLAIN ANALYZE do not replace a database query planner — FiQueLa has no optimizer. The output reflects the fixed execution order defined by the query lifecycle.