ANALYZE TABLE, and statistics that were three months old

The optimiser chooses a plan from statistics it samples, and a table whose distribution has changed since the last sample gets a plan chosen for the old data.

-- the estimate the optimiser is working from
EXPLAIN SELECT ... ;   -- rows: 8100
EXPLAIN ANALYZE ... ;  -- actual rows: 94012

SELECT last_update FROM mysql.innodb_table_stats
WHERE table_name = 'orders';
-- 2020-06-14      ← three months ago

ANALYZE TABLE orders;

A large gap between the estimate and the actual count is the diagnosis, and stale statistics are one of the two causes — the other being a predicate the optimiser cannot estimate at all. ANALYZE TABLE is cheap on InnoDB because it samples rather than scans, and innodb_stats_persistent_sample_pages is the knob when the default sample is too small for a skewed table. Histograms in 8.0 are the better tool for a genuinely skewed column and have to be created explicitly.