1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//! Migration adding a leading-cursor index for no-routing-key subscription scans.
//!
//! The m0004 index `idx_event_type_routing_cursor` places `routing_key` between
//! `aggregator_type` and the cursor/sort columns, so it only helps subscriptions
//! that constrain `routing_key`. A subscription reading with `.all()` has no
//! `routing_key` predicate, so the planner can only use that index up to
//! `aggregator_type=?` — the `timestamp` range becomes unreachable, forcing a full
//! scan of every matching row plus an external sort on every poll.
//!
//! This migration adds a second, complementary index whose cursor columns come
//! immediately after `aggregator_type`, letting the `timestamp > ?` cursor bound
//! push into the index seek so a caught-up poll returns without a scan or sort.
use vec_box;
/// Migration that adds a leading-cursor index for `.all()` subscription scans.
///
/// ## Changes
///
/// - Creates `idx_event_type_cursor` on
/// `(aggregator_type, timestamp, timestamp_subsec, version, id)`.
///
/// ## Notes
///
/// - This is additive: `idx_event_type_routing_cursor` (m0004) is kept, since it
/// still serves subscriptions that filter by `routing_key`.
/// - The trailing `id` is included so the index fully covers the keyset tiebreaker
/// (`id` is the final `ORDER BY` / cursor column), avoiding any residual sort.
/// - It also lets the `latest_timestamp()` query (`MAX(timestamp)` over the same
/// filter) read the index tail.
///
/// ## Dependencies
///
/// This migration depends on [`M0004`](crate::M0004).
;
sqlite_migration!;
mysql_migration!;
postgres_migration!;