Commit 35dddfc
committed
Faster count implementation that's still quite accurate
I wasn't particularly surprised to pop open our PlanetScale report this
morning and see that the count-by-state query used in River UI is now
the demo's most expensive query by cumulative time:
select state, count(*) from river_job group by state
Count: 59,386 · p99: 13,131 ms · Cache hit: 87.5%
This has been a known problem for quite some time both in Postgres and
in River UI. The demo's now up to 1.6M completed rows, so counts are
getting slower by the day.
I was having Codex help brainstorm ways that this could be improved, and
it came up with what I think is quite a clever strategy that should be
very fast with minimum downsides:
* The count endpoint starts out with an optimistic query that tries to
do a full count by all states, but puts a limit of 10k rows on any
particular one.
* If only the constrained 10k+ information is available, that's what's
shown, but we immediately try to get a full exact count of all rows
because even if you have a lot of rows, it's still better to know that
you have 10,001 versus 50k versus 200k, versus 5M. This longer count
is kicked off in the background, and is refreshed every 1-30 minutes,
depending on how long the count is taking. Its results are used when a
reasonably fresh cache value is available so we can show users the
best available number. Even when a cached value is available, we still
prefer a more fresh capped count for states that don't exceed 10k.
* In Postgres, if no cached exactly count is available (most commonly
right after startup), we use a planner estimate to find a rough
number. This value will only be in play for a short time until an
exact count is available.
The type of count (`exact`, `exact_cached`, `estimated`, `lower_bound`)
is communicated o the UI so that it can give context on counts in
tooltips. For example, it might show 12.3M, ≈987.7K, or 10K+ depending
on the situation, along with source and freshness.
I ran a benchmark and you can see that at large numbers doing a bounded
count stays orders of magnitude more responsive. This might seem like a
small thing, but it keeps the UI more up-to-date and responsive even for
very large users, which is very good.
| Rows | Table + indexes | Existing exact count | Bounded count | Planner estimate | Bounded speedup |
|---:|---:|---:|---:|---:|---:|
| 100K | 17 MB | 7.16 ms | 0.93 ms | 0.47 ms | 7.7× |
| 1M | 174 MB | 24.45 ms | 1.09 ms | 0.66 ms | 22× |
| 10M | 1.7 GB | 203.54 ms | 1.01 ms | 0.59 ms | 201× |
> Warm local PostgreSQL 18 averages with all rows in `completed`. The planner estimate includes the `last_analyze` metadata lookup and one state-specific `EXPLAIN`; bounded speedup compares the bounded count with the existing exact count.
> Warm local PostgreSQL 18 averages with all rows in `completed`. The planner estimate includes the `last_analyze` metadata lookup and one state-specific `EXPLAIN`; cold estimated total is bounded count plus planner estimate, and speedup compares that total with the existing exact count.
I'm sort of hoping that this is a nice compromise for all things -- i.e.
fast at small numbers, reasonably fast at large numbers, and still keeps
precise numbers so we don't have to get too abstract. The downside is
more code complexity, but Codex seems to have done a decent job of
implementation (and I tweaked a bunch of stuff for style) and we have
pretty good tests.1 parent dd0d14c commit 35dddfc
10 files changed
Lines changed: 853 additions & 124 deletions
File tree
- internal/querycacher
- src
- components
- services
- utils
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
14 | 18 | | |
15 | 19 | | |
16 | 20 | | |
| |||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
| |||
1054 | 1055 | | |
1055 | 1056 | | |
1056 | 1057 | | |
| 1058 | + | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + | |
| 1075 | + | |
| 1076 | + | |
1057 | 1077 | | |
1058 | 1078 | | |
1059 | 1079 | | |
| |||
1092 | 1112 | | |
1093 | 1113 | | |
1094 | 1114 | | |
1095 | | - | |
1096 | | - | |
1097 | | - | |
1098 | | - | |
1099 | | - | |
1100 | | - | |
1101 | | - | |
1102 | | - | |
1103 | | - | |
1104 | | - | |
| 1115 | + | |
| 1116 | + | |
| 1117 | + | |
| 1118 | + | |
| 1119 | + | |
| 1120 | + | |
| 1121 | + | |
| 1122 | + | |
| 1123 | + | |
1105 | 1124 | | |
1106 | 1125 | | |
1107 | | - | |
| 1126 | + | |
1108 | 1127 | | |
1109 | 1128 | | |
1110 | | - | |
| 1129 | + | |
| 1130 | + | |
| 1131 | + | |
| 1132 | + | |
| 1133 | + | |
| 1134 | + | |
1111 | 1135 | | |
1112 | | - | |
1113 | | - | |
| 1136 | + | |
1114 | 1137 | | |
1115 | 1138 | | |
1116 | 1139 | | |
1117 | | - | |
| 1140 | + | |
1118 | 1141 | | |
| 1142 | + | |
| 1143 | + | |
| 1144 | + | |
| 1145 | + | |
| 1146 | + | |
| 1147 | + | |
| 1148 | + | |
| 1149 | + | |
| 1150 | + | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
| 1155 | + | |
| 1156 | + | |
| 1157 | + | |
| 1158 | + | |
| 1159 | + | |
| 1160 | + | |
| 1161 | + | |
| 1162 | + | |
| 1163 | + | |
| 1164 | + | |
| 1165 | + | |
| 1166 | + | |
| 1167 | + | |
1119 | 1168 | | |
1120 | 1169 | | |
1121 | 1170 | | |
1122 | | - | |
1123 | | - | |
1124 | | - | |
| 1171 | + | |
| 1172 | + | |
| 1173 | + | |
| 1174 | + | |
| 1175 | + | |
1125 | 1176 | | |
1126 | 1177 | | |
1127 | | - | |
| 1178 | + | |
1128 | 1179 | | |
1129 | 1180 | | |
1130 | | - | |
| 1181 | + | |
| 1182 | + | |
| 1183 | + | |
| 1184 | + | |
| 1185 | + | |
| 1186 | + | |
1131 | 1187 | | |
1132 | | - | |
1133 | | - | |
| 1188 | + | |
1134 | 1189 | | |
1135 | 1190 | | |
1136 | 1191 | | |
1137 | | - | |
| 1192 | + | |
1138 | 1193 | | |
1139 | 1194 | | |
| 1195 | + | |
| 1196 | + | |
| 1197 | + | |
1140 | 1198 | | |
1141 | 1199 | | |
1142 | | - | |
1143 | | - | |
1144 | | - | |
| 1200 | + | |
| 1201 | + | |
| 1202 | + | |
| 1203 | + | |
| 1204 | + | |
| 1205 | + | |
| 1206 | + | |
| 1207 | + | |
| 1208 | + | |
| 1209 | + | |
| 1210 | + | |
| 1211 | + | |
| 1212 | + | |
| 1213 | + | |
| 1214 | + | |
| 1215 | + | |
| 1216 | + | |
| 1217 | + | |
| 1218 | + | |
| 1219 | + | |
| 1220 | + | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + | |
| 1224 | + | |
| 1225 | + | |
| 1226 | + | |
| 1227 | + | |
| 1228 | + | |
| 1229 | + | |
| 1230 | + | |
| 1231 | + | |
| 1232 | + | |
| 1233 | + | |
| 1234 | + | |
| 1235 | + | |
| 1236 | + | |
| 1237 | + | |
| 1238 | + | |
| 1239 | + | |
| 1240 | + | |
| 1241 | + | |
| 1242 | + | |
| 1243 | + | |
| 1244 | + | |
| 1245 | + | |
| 1246 | + | |
| 1247 | + | |
| 1248 | + | |
| 1249 | + | |
| 1250 | + | |
| 1251 | + | |
| 1252 | + | |
| 1253 | + | |
| 1254 | + | |
| 1255 | + | |
| 1256 | + | |
| 1257 | + | |
1145 | 1258 | | |
| 1259 | + | |
| 1260 | + | |
| 1261 | + | |
| 1262 | + | |
| 1263 | + | |
| 1264 | + | |
| 1265 | + | |
| 1266 | + | |
| 1267 | + | |
| 1268 | + | |
| 1269 | + | |
| 1270 | + | |
| 1271 | + | |
| 1272 | + | |
| 1273 | + | |
| 1274 | + | |
| 1275 | + | |
| 1276 | + | |
| 1277 | + | |
| 1278 | + | |
| 1279 | + | |
| 1280 | + | |
| 1281 | + | |
| 1282 | + | |
| 1283 | + | |
| 1284 | + | |
| 1285 | + | |
| 1286 | + | |
| 1287 | + | |
| 1288 | + | |
| 1289 | + | |
| 1290 | + | |
| 1291 | + | |
| 1292 | + | |
| 1293 | + | |
| 1294 | + | |
| 1295 | + | |
| 1296 | + | |
| 1297 | + | |
| 1298 | + | |
| 1299 | + | |
| 1300 | + | |
| 1301 | + | |
| 1302 | + | |
| 1303 | + | |
| 1304 | + | |
| 1305 | + | |
| 1306 | + | |
| 1307 | + | |
| 1308 | + | |
| 1309 | + | |
| 1310 | + | |
| 1311 | + | |
| 1312 | + | |
| 1313 | + | |
| 1314 | + | |
| 1315 | + | |
| 1316 | + | |
| 1317 | + | |
| 1318 | + | |
| 1319 | + | |
| 1320 | + | |
| 1321 | + | |
| 1322 | + | |
| 1323 | + | |
| 1324 | + | |
| 1325 | + | |
| 1326 | + | |
| 1327 | + | |
| 1328 | + | |
| 1329 | + | |
| 1330 | + | |
| 1331 | + | |
| 1332 | + | |
| 1333 | + | |
| 1334 | + | |
| 1335 | + | |
| 1336 | + | |
| 1337 | + | |
| 1338 | + | |
| 1339 | + | |
| 1340 | + | |
| 1341 | + | |
1146 | 1342 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
31 | 39 | | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
32 | 44 | | |
33 | 45 | | |
34 | 46 | | |
35 | 47 | | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
36 | 52 | | |
37 | 53 | | |
38 | | - | |
39 | | - | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
40 | 57 | | |
41 | 58 | | |
42 | 59 | | |
| |||
76 | 93 | | |
77 | 94 | | |
78 | 95 | | |
79 | | - | |
| 96 | + | |
80 | 97 | | |
81 | 98 | | |
82 | 99 | | |
| |||
104 | 121 | | |
105 | 122 | | |
106 | 123 | | |
107 | | - | |
108 | | - | |
109 | | - | |
110 | | - | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
111 | 129 | | |
112 | 130 | | |
113 | 131 | | |
114 | 132 | | |
115 | 133 | | |
116 | 134 | | |
117 | | - | |
118 | | - | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
119 | 140 | | |
120 | 141 | | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
121 | 154 | | |
122 | 155 | | |
123 | 156 | | |
| |||
0 commit comments