# union — benchmark

Workload: 10_000 rows; `filter(active) ∪ filter(val > 50)`. Tick mutates
either `active` or `val` on one row. Batch streams 1000 such ticks.
Generated by [comparisons/bench/operators/union.bench.ts](../../comparisons/bench/operators/union.bench.ts).

| Library | Setup (ms) | Single (ms) | vs data | Batch 1000 (ms) | vs data |
|---|---:|---:|---:|---:|---:|
| **data** | 4.65 | **0.084** | — | **2.98** | — |
| svelte-store | 1.03 | 0.407 | 4.8× | 427.94 | 144× |
| rxjs | 1.17 | 0.449 | 5.3× | 431.69 | 145× |
| react | 1.24 | 0.469 | 5.6× | 384.59 | 129× |
| preact-signals | 2.22 | 0.729 | 8.7× | 23.79 | 8.0× |
| solid | 4.86 | 2.36 | 28.1× | 81.79 | 27.4× |
| mobx | 119.01 | 8.78 | 105× | 218.33 | 73.3× |
| vue-reactivity | 23.11 | 15.41 | 183× | 744.26 | 250× |



crossfilter omitted — no native union primitive (dimensions only AND).

data is fastest on both single (5.5x over rxjs) and batch (9.5x over
preact-signals).

## How

`union` uses the same bitmask machinery as `intersect`/`except`: a row
enters the output when *any* bit is set (`bits !== 0`).
O(1) per per-source delta.

Run `BENCH_OPS=union npm run bench:ops` to refresh.
