-- ============================================================ -- SP-GiST Orbital Trie Benchmark (Phase 3) -- CelesTrak active catalog, ~14k satellites -- GiST comparison omitted (known crash in gist_tle_picksplit) -- ============================================================ \timing on -- ============================================================ -- 1. Catalog distribution analysis -- ============================================================ SELECT CASE WHEN tle_perigee(tle) < 2000 THEN 'LEO (<2000km)' WHEN tle_perigee(tle) < 20000 THEN 'MEO (2000-20000km)' WHEN tle_perigee(tle) < 34000 THEN 'GEO-transfer' ELSE 'GEO/HEO (>34000km)' END AS regime, count(*) AS n, round(100.0 * count(*) / (SELECT count(*) FROM bench_catalog), 1) AS pct FROM bench_catalog GROUP BY 1 ORDER BY 2 DESC; -- ============================================================ -- 2. Create SP-GiST index -- ============================================================ \echo '--- CREATE SP-GiST INDEX ---' CREATE INDEX bench_spgist ON bench_catalog USING spgist (tle tle_spgist_ops); SELECT pg_size_pretty(pg_relation_size('bench_spgist'::regclass)) AS spgist_size; -- ============================================================ -- 3. Benchmark: 2h window, Eagle Idaho (43.7N) — RAAN active -- ============================================================ \echo '--- BENCHMARK 1: 2h window, Eagle Idaho, 10 deg min_el ---' -- 3a. Sequential scan (baseline) SET enable_indexscan = off; SET enable_bitmapscan = off; \echo 'Sequential scan:' EXPLAIN ANALYZE SELECT count(*) AS candidates FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 10.0 )::observer_window; RESET enable_indexscan; RESET enable_bitmapscan; -- 3b. SP-GiST index scan SET enable_seqscan = off; \echo 'SP-GiST index scan:' EXPLAIN ANALYZE SELECT count(*) AS candidates FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 10.0 )::observer_window; RESET enable_seqscan; -- ============================================================ -- 4. Benchmark: 24h window, Eagle Idaho — RAAN bypassed -- ============================================================ \echo '--- BENCHMARK 2: 24h window, Eagle Idaho, 10 deg min_el ---' SET enable_indexscan = off; SET enable_bitmapscan = off; \echo 'Sequential scan:' SELECT count(*) AS seqscan_24h FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 00:00:00+00'::timestamptz, '2026-02-18 00:00:00+00'::timestamptz, 10.0 )::observer_window; RESET enable_indexscan; RESET enable_bitmapscan; SET enable_seqscan = off; \echo 'SP-GiST index scan:' SELECT count(*) AS spgist_24h FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 00:00:00+00'::timestamptz, '2026-02-18 00:00:00+00'::timestamptz, 10.0 )::observer_window; RESET enable_seqscan; -- ============================================================ -- 5. Benchmark: 2h window, Equatorial observer -- ============================================================ \echo '--- BENCHMARK 3: 2h window, Equator, 10 deg min_el ---' SET enable_indexscan = off; SET enable_bitmapscan = off; \echo 'Sequential scan:' SELECT count(*) AS seqscan_equator FROM bench_catalog WHERE tle &? ROW( observer('0.0N 0.0E 0m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 10.0 )::observer_window; RESET enable_indexscan; RESET enable_bitmapscan; SET enable_seqscan = off; \echo 'SP-GiST index scan:' SELECT count(*) AS spgist_equator FROM bench_catalog WHERE tle &? ROW( observer('0.0N 0.0E 0m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 10.0 )::observer_window; RESET enable_seqscan; -- ============================================================ -- 6. Benchmark: High min_el (45 deg) -- ============================================================ \echo '--- BENCHMARK 4: 2h window, Eagle Idaho, 45 deg min_el ---' SET enable_indexscan = off; SET enable_bitmapscan = off; \echo 'Sequential scan:' SELECT count(*) AS seqscan_45deg FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 45.0 )::observer_window; RESET enable_indexscan; RESET enable_bitmapscan; SET enable_seqscan = off; \echo 'SP-GiST index scan:' SELECT count(*) AS spgist_45deg FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 45.0 )::observer_window; RESET enable_seqscan; -- ============================================================ -- 7. Consistency check -- ============================================================ \echo '--- CONSISTENCY CHECK ---' SET enable_indexscan = off; SET enable_bitmapscan = off; CREATE TEMPORARY TABLE seq_results AS SELECT norad_id FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 10.0 )::observer_window; RESET enable_indexscan; RESET enable_bitmapscan; SET enable_seqscan = off; CREATE TEMPORARY TABLE idx_results AS SELECT norad_id FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 10.0 )::observer_window; RESET enable_seqscan; SELECT count(*) AS in_seq_not_idx FROM seq_results WHERE norad_id NOT IN (SELECT norad_id FROM idx_results); SELECT count(*) AS in_idx_not_seq FROM idx_results WHERE norad_id NOT IN (SELECT norad_id FROM seq_results); DROP TABLE seq_results, idx_results; -- ============================================================ -- 8. Pruning summary -- ============================================================ \echo '--- PRUNING SUMMARY ---' SELECT '2h/Eagle/10deg' AS scenario, (SELECT count(*) FROM bench_catalog) AS catalog_size, count(*) AS candidates, round(100.0 * count(*) / (SELECT count(*) FROM bench_catalog), 1) AS candidate_pct, round(100.0 * (1.0 - count(*)::numeric / (SELECT count(*) FROM bench_catalog)), 1) AS pruning_pct FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 10.0 )::observer_window UNION ALL SELECT '24h/Eagle/10deg', (SELECT count(*) FROM bench_catalog), count(*), round(100.0 * count(*) / (SELECT count(*) FROM bench_catalog), 1), round(100.0 * (1.0 - count(*)::numeric / (SELECT count(*) FROM bench_catalog)), 1) FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 00:00:00+00'::timestamptz, '2026-02-18 00:00:00+00'::timestamptz, 10.0 )::observer_window UNION ALL SELECT '2h/Equator/10deg', (SELECT count(*) FROM bench_catalog), count(*), round(100.0 * count(*) / (SELECT count(*) FROM bench_catalog), 1), round(100.0 * (1.0 - count(*)::numeric / (SELECT count(*) FROM bench_catalog)), 1) FROM bench_catalog WHERE tle &? ROW( observer('0.0N 0.0E 0m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 10.0 )::observer_window UNION ALL SELECT '2h/Eagle/45deg', (SELECT count(*) FROM bench_catalog), count(*), round(100.0 * count(*) / (SELECT count(*) FROM bench_catalog), 1), round(100.0 * (1.0 - count(*)::numeric / (SELECT count(*) FROM bench_catalog)), 1) FROM bench_catalog WHERE tle &? ROW( observer('43.6977N 116.3535W 760m'), '2026-02-17 02:00:00+00'::timestamptz, '2026-02-17 04:00:00+00'::timestamptz, 45.0 )::observer_window; -- ============================================================ -- Cleanup -- ============================================================ DROP INDEX bench_spgist; DROP TABLE bench_catalog; \timing off