Overview
Modern data lakehouse architectures store petabytes of data in columnar Apache Parquet format. Traditional row-oriented query engines pay steep penalties when executing analytical queries because they deserialize full rows and invoke virtual function calls per record.
This project implements a vectorized columnar query execution engine in C++20. By operating on batches of 2,048 column values at a time, the engine achieves instruction-level parallelism, branch-free filtering via bitmasks, and direct dictionary-encoded evaluation.
Core Technical Features
1. Vectorized Late Materialization
Filter conditions are evaluated against dictionary IDs and min/max statistics stored in Parquet row-group footers before reading raw uncompressed column payloads. This skips up to 80% of disk I/O for selective queries.
2. SIMD Bitmask Filtering
Instead of conditional branches (if (x > 10)), the engine issues AVX2 vector comparison intrinsics that produce a 256-bit mask, selecting valid vector indexes in a single CPU cycle.
#include <immintrin.h>
#include <span>
void filter_gt_avx2(
std::span<const float> values,
float threshold,
std::span<uint8_t> selection_mask
) {
__m256 thresh_vec = _mm256_set1_ps(threshold);
size_t i = 0;
// Process 8 floats per SIMD vector iteration
for (; i + 8 <= values.size(); i += 8) {
__m256 val_vec = _mm256_loadu_ps(&values[i]);
__m256 cmp_res = _mm256_cmp_ps(val_vec, thresh_vec, _CMP_GT_OQ);
int mask = _mm256_movemask_ps(cmp_res);
selection_mask[i / 8] = static_cast<uint8_t>(mask);
}
}
Performance & Insights
- Zero Memory Allocation in Hot Loop: Memory for intermediate columnar vectors is allocated upfront in fixed-size slab memory arenas, eliminating memory fragmentation.
- Cache-Locality: Columnar batches fit entirely within L1/L2 CPU caches during multi-stage aggregation pipelines.