|
| 1 | +# DuckShop 10K |
| 2 | + |
| 3 | +A deterministic generator for a ten-thousand-model SQLBuild project in Snowflake SQL. It describes |
| 4 | +Mallard & Co., the fictional duck-themed home goods business of the |
| 5 | +[DuckShop](../duckshop/README.md) project, after a decade of growth: 40 storefronts in 10 regions, |
| 6 | +marketplace partners, carriers, warehouses, retail stores, suppliers, payment gateways, ad |
| 7 | +networks, messaging, affiliates, support tools, ledgers, wholesale desks, returns portals and a |
| 8 | +product catalogue. Every name and value is invented. |
| 9 | + |
| 10 | +Only the generator, its tests and `checksum.txt` are committed. The generated project is written |
| 11 | +to a directory you choose. |
| 12 | + |
| 13 | +## Usage |
| 14 | + |
| 15 | +```bash |
| 16 | +python benchmarks/duckshop-10k/generate.py --out /path/to/duckshop-10k # write the project |
| 17 | +python benchmarks/duckshop-10k/generate.py --verify /path/to/duckshop-10k # check a written copy |
| 18 | +python benchmarks/duckshop-10k/generate.py --check # check an in-memory build |
| 19 | +cd /path/to/duckshop-10k && sqb compile # no warehouse connection needed |
| 20 | +``` |
| 21 | + |
| 22 | +`--profile smoke` writes a small project of about 1,100 models with the same templates, for fast |
| 23 | +iteration. `checksum.txt` records the full profile only. |
| 24 | + |
| 25 | +## Determinism and versioning |
| 26 | + |
| 27 | +The generator uses no randomness, clocks or environment: the same generator version always writes |
| 28 | +byte-identical files. `checksum.txt` holds the generator version, the file count and the SHA-256 of |
| 29 | +`MANIFEST.sha256`, a sorted list of the SHA-256 of every generated file. |
| 30 | + |
| 31 | +When a change alters any generated file, bump `GENERATOR_VERSION` in `duckshop10k/__init__.py` and |
| 32 | +run `python benchmarks/duckshop-10k/generate.py --update-checksum`. |
| 33 | + |
| 34 | +## Shape |
| 35 | + |
| 36 | +| | Count | |
| 37 | +|---|---| |
| 38 | +| Models | 10,282 | |
| 39 | +| Staging, intermediate, marts and snapshots | 6,149 (59.8%), 1,961 (19.1%), 2,162 (21.0%), 10 | |
| 40 | +| Sources | 2,466 table sources and one expression source | |
| 41 | +| Unit tests and scenarios | 288 and 2 | |
| 42 | +| Dependency depth | 11 at most; 168 models at depth 7 or more | |
| 43 | + |
| 44 | +Most models read one to four upstreams; a few dozen wide marts, unions and scorecards read ten or |
| 45 | +more. Staging deduplicates change logs with a change-log macro, types three platform layouts |
| 46 | +(legacy columns with local times, typed columns with offset times, and JSON documents with epoch |
| 47 | +times) and flattens arrays into child models. The intermediate layer converts every instance to a |
| 48 | +shared shape (UTC times, major-unit amounts, mapped statuses), enriches headers with child totals, |
| 49 | +unions instances by region and company, converts currencies with `ASOF JOIN`, sessionises |
| 50 | +clickstream events in microbatches and builds customer identity, value and segment models and a |
| 51 | +budget variance chain. Marts give every instance, team and region its reports, and publish facts and |
| 52 | +dimensions with enforced contracts. |
| 53 | + |
| 54 | +The models that use `HASH`, `TIMESTAMP_LTZ` or `CURRENT_TIMESTAMP()` are tagged `known_divergence`, |
| 55 | +because their results depend on the engine or the session. |
| 56 | + |
| 57 | +## Checks |
| 58 | + |
| 59 | +- `benchmarks/duckshop-10k/tests/` checks the shape, the determinism of two builds, the recorded |
| 60 | + checksum and the generated custom Rule's tests, offline. |
| 61 | +- `tests/e2e/.../compile/test_duckshop_10k_compile.py` generates the project, verifies it against |
| 62 | + `checksum.txt` and compiles it cold with the checkout's build, requiring zero errors and zero |
| 63 | + warnings. |
| 64 | + |
| 65 | +CI runs both in the 10,000-model cell of the dense compile job, under its 4 GiB memory limit, after |
| 66 | +the dense guards have finished, so the DuckShop compile never shares the limit with them. |
0 commit comments