This project simulates a time-series sensor workload (~600k+ rows) in PostgreSQL and evaluates how query selectivity affects execution plans.
The goal is to demonstrate:
- Composite index design
- Cost-based optimization
- Sequential vs Index Scan behavior
- Performance benchmarking using EXPLAIN ANALYZE
predictive-maintenance-sql
│
├── python
│ └── load_readings.py
│
├── sql
│ ├── 000_reset.sql
│ ├── 001_schema.sql
│ ├── 002_seed.sql
│ ├── 003_queries.sql
│ ├── 004_indexes.sql
│ ├── 005_explain.sql
│ ├── 005b_explain_range.sql
│ └── 005c_explain_fixed.sql
│
├── run_all.ps1
└── README.md
- Table: sensor_readings
- Rows: ~600,005
- Composite index: (sensor_id, ts)
- Workload: time-range aggregate queries on a single sensor
.\run_all.ps1
createdb predictive_maintenance
psql -d predictive_maintenance -f sql/001_schema.sql psql -d predictive_maintenance -f sql/002_seed.sql psql -d predictive_maintenance -f sql/004_indexes.sql
python -u python/load_readings.py
psql -d predictive_maintenance -f sql/005c_explain_fixed.sql
Query:
SELECT AVG(value) FROM sensor_readings WHERE sensor_id = 1 AND ts >= NOW() - INTERVAL '10 minutes';
Execution plan:
Parallel Sequential Scan
- 143 ms
Explanation:
When a query matches a large portion of the table, PostgreSQL estimates that scanning the table sequentially is cheaper than performing many index lookups. The planner therefore chooses a Parallel Sequential Scan, even though an index exists.
Query:
SELECT AVG(value) FROM sensor_readings WHERE sensor_id = 1 AND ts BETWEEN <fixed_timestamp - 30 seconds> AND <fixed_timestamp>;
Execution plan with index:
Index Scan using idx_sensor_readings_sensor_ts
- 0.067 ms
Execution plan without index:
Parallel Sequential Scan
- 143 ms
This demonstrates a ~2100× performance improvement when the query predicate is highly selective.
-
Index presence alone does not guarantee index usage.
-
Query selectivity determines planner behavior.
-
Broad analytical filters often favor Parallel Seq Scans.
-
Highly selective predicates benefit significantly from composite indexing.
-
PostgreSQL dynamically chooses the lowest estimated execution cost.
Execution times may vary depending on:
-
Hardware
-
PostgreSQL configuration
-
Cache state
-
However, the planner behavior (Seq Scan vs Index Scan) should remain consistent given similar dataset size and query selectivity.
Rosaliz García Computer Science – Data Science Track