Skip to content

core-interop: SchemaView-based ECSchemaProvider#1394

Draft
grigasp wants to merge 10 commits into
nextfrom
core-interop/schemaview-provider
Draft

core-interop: SchemaView-based ECSchemaProvider#1394
grigasp wants to merge 10 commits into
nextfrom
core-interop/schemaview-provider

Conversation

@grigasp

@grigasp grigasp commented Jun 9, 2026

Copy link
Copy Markdown
Member

No description provided.

@changeset-bot

changeset-bot Bot commented Jun 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2170ba7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@itwin/presentation-shared Minor
@itwin/presentation-core-interop Minor
@itwin/presentation-hierarchies Patch
@itwin/presentation-hierarchies-react Patch
@itwin/unified-selection Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@grigasp

grigasp commented Jun 10, 2026

Copy link
Copy Markdown
Member Author

SchemaView-based ECSchemaProvider in benchmark tests

These tests use synthetic datasets, so might not necessarily represent real world scenario, but should give a good indication of what to expect.

Unified selection

Test Baseline SchemaView
compute selection for 50k elements 297 ms 263 ms (-11.4%)
compute parent selection for 50k elements 294 ms 279 ms (-5.1%)
compute top ancestor selection for 50k elements 455 ms 447 ms (-1.8%)
compute category selection for 50k elements 93 ms 95 ms (+2.2%)
compute model selection for 50k elements 75 ms 64 ms (-14.7%)
compute functional selection for 50k 3D elements 371 ms 375 ms (+1.1%)
compute parent functional selection for 50k 3D elements 392 ms 358 ms (-8.7%)
compute top ancestor functional selection for 50k 3D elements 908 ms 857 ms (-5.6%)
compute functional selection for 50k 2D elements 2280 ms 2349 ms (+3.0%)
compute parent functional selection for 50k 2D elements 2258 ms 2318 ms (+2.7%)
compute top ancestor functional selection for 50k 2D elements 2254 ms 2440 ms (+8.3%)
hilite 50k elements 1500 ms 1447 ms (-3.5%)
hilite 50k group elements 212 ms 204 ms (-3.8%)
hilite 1k subjects 30247 ms 29331 ms (-3.0%)
hilite 50k subcategories 250 ms 210 ms (-16.0%)
hilite 50k functional 3D elements 23000 ms 21614 ms (-6.0%)
hilite 50k functional 2D elements 5765 ms 5257 ms (-8.8%)

TLDR; More or less within error.

Hierarchies

Test Baseline SchemaView
grouping by label 19551 ms 21177 ms (+8.3%)
grouping by class 22408 ms 21111 ms (-5.8%)
grouping by property 21950 ms 21654 ms (-1.3%)
grouping by base class (10 classes) 68486 ms 70980 ms (+3.6%)
grouping by multiple attributes 98992 ms 101764 ms (+2.8%)
models tree initial (Baytown) 81 ms 156 ms (+92.6%)
models tree full (Baytown) 87322 ms 45069 ms (-48.4%)
models tree creates initial filtered view for 50k target items 4087 ms 4224 ms (+3.4%)
hide if no children required to finalize root, w/o children 33225 ms 29413 ms (-11.5%)
hide if no children required to finalize root, w/ children 189 ms 111 ms (-41.3%)
search searches with 50000 paths 8514 ms 8633 ms (+1.4%)
flat 50k elements list 4933 ms 4227 ms (-14.3%)

TLDR; Most within error, except 1 significant improvement - "models tree full (Baytown)" (87322 ms -> 45069 ms),


Next, I'll try this implementation on our real-world iModels using Models tree & Consolidated content descriptor tests.

@grigasp

grigasp commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

Presentation performance tests: local backend

Local backend means it's running in a process on the same machine and has iModel fully available (no need to download any V2 checkpoint blocks).

Comparison of median local run times between schema-context (baseline) and schema-view (new). Negative deltas mean schema-view is faster.

TS Consolidated content descriptor

iModel schema-context (s) schema-view (s) Δ (s) Δ (%)
L - 1 4.071 2.250 -1.821 -44.7%
L - 2 15.037 10.259 -4.778 -31.8%
L - 3 4.523 2.620 -1.903 -42.1%
L - 4 17.257 12.020 -5.237 -30.3%
L - 5 32.264 27.619 -4.645 -14.4%
L - 6 2.456 2.214 -0.242 -9.9%
L - 7 1.354 1.035 -0.319 -23.6%
L - 8 9.632 5.884 -3.748 -38.9%
M - 1 0.883 0.746 -0.137 -15.5%
M - 2 1.305 1.025 -0.280 -21.5%
M - 3 4.285 3.061 -1.224 -28.6%
M - 4 10.052 3.034 -7.018 -69.8%
M - 5 1.002 0.630 -0.372 -37.1%
M - 6 1.900 1.457 -0.443 -23.3%
M - 7 0.298 0.207 -0.091 -30.5%
M - 8 0.181 0.166 -0.015 -8.3%
M - 9 1.183 1.090 -0.093 -7.9%
M - 10 0.311 0.208 -0.103 -33.1%
M - 11 0.716 0.626 -0.090 -12.6%
M - 12 0.166 0.136 -0.030 -18.1%
M - 13 0.489 0.386 -0.103 -21.1%
M - 14 0.431 0.359 -0.072 -16.7%
S - 1 1.354 0.465 -0.889 -65.7%
S - 2 0.416 0.295 -0.121 -29.1%
S - 3 0.099 0.085 -0.014 -14.1%
S - 4 0.113 0.069 -0.044 -38.9%
S - 5 0.543 0.276 -0.267 -49.2%
S - 6 0.114 0.103 -0.011 -9.6%
S - 7 0.104 0.083 -0.021 -20.2%
XL - 1 47.192 46.277 -0.915 -1.9%
XL - 2 36.075 22.677 -13.398 -37.1%
XL - 3 43.213 39.552 -3.661 -8.5%
XL - 4 26.595 22.293 -4.302 -16.2%
XL - 5 43.993 37.673 -6.320 -14.4%
XL - 6 32.220 29.764 -2.456 -7.6%
XL - 7 2.538 3.040 +0.502 +19.8%
L - 9 21.222 17.088 -4.134 -19.5%
L - 10 8.513 5.220 -3.293 -38.7%
M - 15 5.609 2.626 -2.983 -53.2%

Summary: schema-view is faster in 38 of 39 cases. Aggregate time dropped from 379.7 s to 304.6 s (-19.8% overall). The largest relative wins are on small/medium iModels (e.g. M - 4 -69.8%, S - 1 -65.7%, M - 15 -53.2%), while the largest absolute saving is XL - 2 (-13.4 s). The only regression is XL - 7 (+0.5 s / +19.8%), and XL - 1 is essentially unchanged (-1.9%). Heavy XL models improve proportionally less, suggesting the gain is mostly in fixed per-request overhead rather than raw query work.

Models tree initial load

iModel schema-context (s) schema-view (s) Δ (s) Δ (%)
S - 1 0.084 0.109 +0.025 +29.8%
S - 2 0.118 0.057 -0.061 -51.7%
S - 3 0.076 0.059 -0.017 -22.4%
S - 4 0.073 0.047 -0.026 -35.6%
S - 5 0.097 0.095 -0.002 -2.1%
S - 6 0.072 0.057 -0.015 -20.8%
S - 7 0.093 0.056 -0.037 -39.8%
M - 1 0.086 0.070 -0.016 -18.6%
M - 2 0.084 0.121 +0.037 +44.0%
M - 3 0.106 0.217 +0.111 +104.7%
M - 4 0.149 1.168 +1.019 +683.9%
M - 5 0.104 0.098 -0.006 -5.8%
M - 6 0.141 0.114 -0.027 -19.1%
M - 7 0.089 0.055 -0.034 -38.2%
M - 8 0.096 0.053 -0.043 -44.8%
M - 9 0.096 0.055 -0.041 -42.7%
M - 10 0.121 0.062 -0.059 -48.8%
M - 11 0.085 0.060 -0.025 -29.4%
M - 12 0.092 0.055 -0.037 -40.2%
M - 13 0.100 0.065 -0.035 -35.0%
M - 14 0.095 0.056 -0.039 -41.1%
M - 15 0.078 0.371 +0.293 +375.6%
L - 1 0.137 0.408 +0.271 +197.8%
L - 2 0.095 0.602 +0.507 +533.7%
L - 3 0.097 0.237 +0.140 +144.3%
L - 4 0.182 0.788 +0.606 +333.0%
L - 5 0.171 0.771 +0.600 +350.9%
L - 6 0.103 0.063 -0.040 -38.8%
L - 7 0.102 0.061 -0.041 -40.2%
L - 8 0.088 0.539 +0.451 +512.5%
L - 9 0.152 0.773 +0.621 +408.6%
L - 10 0.081 0.361 +0.280 +345.7%
XL - 1 0.120 0.050 -0.070 -58.3%
XL - 2 0.132 1.264 +1.132 +857.6%
XL - 3 0.204 0.696 +0.492 +241.2%
XL - 4 0.222 0.622 +0.400 +180.2%
XL - 5 4.528 4.271 -0.257 -5.7%
XL - 6 0.234 0.260 +0.026 +11.1%
XL - 7 0.152 0.065 -0.087 -57.2%

Summary: The aggregate grows from 8.94 s to 14.93 s (+67%). The split is 22 faster / 17 slower. Wins are concentrated in small/medium models and a couple of XL models that do little first-load work (XL - 1 -58.3%, XL - 7 -57.2%, S - 2 -51.7%). The remaining regression is driven by a handful of models that do real first-load query work: XL - 2 +1.13 s, M - 4 +1.02 s, L - 9 +0.62 s, L - 4 / L - 5 ~+0.60 s.

Models tree first branch

iModel schema-context (s) schema-view (s) Δ (s) Δ (%)
S - 1 0.402 0.214 -0.188 -46.8%
S - 2 0.282 0.154 -0.128 -45.4%
S - 3 0.164 0.160 -0.004 -2.4%
S - 4 0.121 0.132 +0.011 +9.1%
S - 5 0.313 0.179 -0.134 -42.8%
S - 6 0.161 0.129 -0.032 -19.9%
S - 7 0.144 0.124 -0.020 -13.9%
M - 1 0.486 0.395 -0.091 -18.7%
M - 2 0.686 0.362 -0.324 -47.2%
M - 3 1.386 1.727 +0.341 +24.6%
M - 4 6.050 3.511 -2.539 -42.0%
M - 5 0.566 0.235 -0.331 -58.5%
M - 6 1.162 1.278 +0.116 +10.0%
M - 7 0.338 0.342 +0.004 +1.2%
M - 8 0.250 0.243 -0.007 -2.8%
M - 9 0.867 0.907 +0.040 +4.6%
M - 10 0.246 0.231 -0.015 -6.1%
M - 11 0.666 0.654 -0.012 -1.8%
M - 12 0.189 0.186 -0.003 -1.6%
M - 13 0.416 0.428 +0.012 +2.9%
M - 14 0.998 0.971 -0.027 -2.7%
M - 15 1.569 2.295 +0.726 +46.3%
L - 1 3.550 3.741 +0.191 +5.4%
L - 2 12.225 11.652 -0.573 -4.7%
L - 3 4.003 4.070 +0.067 +1.7%
L - 4 15.397 15.195 -0.202 -1.3%
L - 5 26.584 26.991 +0.407 +1.5%
L - 6 1.859 1.743 -0.116 -6.2%
L - 7 1.221 1.162 -0.059 -4.8%
L - 8 3.618 1.389 -2.229 -61.6%
L - 9 16.363 13.504 -2.859 -17.5%
L - 10 8.263 6.169 -2.094 -25.3%
XL - 1 78.344 84.589 +6.245 +8.0%
XL - 2 7.283 8.301 +1.018 +14.0%
XL - 3 11.500 11.984 +0.484 +4.2%
XL - 4 25.926 19.991 -5.935 -22.9%
XL - 5 26.121 23.639 -2.482 -9.5%
XL - 6 0.441 0.563 +0.122 +27.7%
XL - 7 0.722 0.668 -0.054 -7.5%

Summary: The suite is essentially at parity — the aggregate edges down from 260.88 s to 250.21 s (-4.1%, or -9.3% excluding the dominant XL - 1 case), split 25 faster / 14 slower. Several heavy models actually improve under schema-viewXL - 4 -22.9 %, L - 8 -61.6 %, L - 10 -25.3 %, L - 9 -17.5 %, M - 4 -42.0 %. Remaining regressions are small in absolute terms (XL - 1 +6.2 s, XL - 2 +1.0 s, M - 15 +0.7 s).

Overall

The content-descriptor suite clearly favors schema-view (-19.8% overall, 38 of 39 faster). On a min-of-all-runs basis the tree suites are roughly neutral: Models tree first branch is at parity / marginally faster (-4.1% aggregate, 25 of 39 faster), and Models tree initial load shows a real but modest regression (+67% aggregate, 22 of 39 faster) concentrated in a handful of models that do actual first-load query work. Net: schema-view is a clear win for content descriptors and broadly neutral for the tree paths, with initial-load worth a closer look on the few real-work models that still regress.

@grigasp

grigasp commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

Presentation performance tests: remote backend

Comparison of remote run times between schema-context (baseline) and schema-view (new). Negative deltas mean schema-view is faster. The iModel column uses anonymized names.

TS Consolidated content descriptor

iModel schema-context (s) schema-view (s) Δ (s) Δ (%)
S - 1 1.750 1.088 -0.662 -37.8%
S - 2 1.531 0.893 -0.638 -41.7%
S - 3 2.551 1.167 -1.384 -54.3%
S - 4 1.344 0.858 -0.486 -36.2%
S - 5 2.376 1.243 -1.133 -47.7%
S - 6 2.072 0.866 -1.206 -58.2%
S - 7 1.338 0.858 -0.480 -35.9%
S - 8 1.652 1.560 -0.092 -5.6%
M - 1 2.760 1.679 -1.081 -39.2%
M - 2 2.238 1.369 -0.869 -38.8%
M - 3 2.291 1.313 -0.978 -42.7%
M - 4 3.213 1.998 -1.215 -37.8%
M - 5 4.809 3.356 -1.453 -30.2%
M - 6 1.901 1.495 -0.406 -21.4%
M - 7 2.023 0.949 -1.074 -53.1%
M - 8 1.835 1.389 -0.446 -24.3%
M - 9 8.838 4.522 -4.316 -48.8%
M - 10 1.474 0.912 -0.562 -38.1%
M - 11 1.520 0.977 -0.543 -35.7%
M - 12 1.317 0.899 -0.418 -31.7%
M - 13 1.662 0.938 -0.724 -43.6%
M - 14 1.496 0.863 -0.633 -42.3%
M - 15 5.635 1.968 -3.667 -65.1%
L - 1 63.351 13.393 -49.958 -78.9%
L - 2 12.382 7.087 -5.295 -42.8%
L - 3 3.210 1.909 -1.301 -40.5%
L - 4 4.721 2.786 -1.935 -41.0%
L - 5 7.924 5.123 -2.801 -35.3%
L - 6 4.521 1.114 -3.407 -75.4%
L - 7 12.234 4.869 -7.365 -60.2%
L - 8 6.506 3.967 -2.539 -39.0%
L - 9 26.970 8.435 -18.535 -68.7%
L - 10 8.568 2.436 -6.132 -71.6%
XL - 1 33.168 11.147 -22.021 -66.4%
XL - 2 42.139 19.533 -22.606 -53.6%
XL - 3 42.492 10.511 -31.981 -75.3%
XL - 4 32.941 15.969 -16.972 -51.5%
XL - 5 8.918 1.977 -6.941 -77.8%
XL - 6 52.001 10.859 -41.142 -79.1%
XL - 7 88.373 13.412 -74.961 -84.8%
XL - 8 12.591 2.977 -9.614 -76.4%
XL - 9 49.083 19.885 -29.198 -59.5%
Other - 1 1.661 0.970 -0.691 -41.6%

Summary: schema-view is faster in all 43 cases. Aggregate time dropped from 571.4 s to 191.5 s (-66.5% overall) — a far larger win than the local runs, since the remote path also pays for schema/metadata round-trips that schema-view removes. The biggest absolute saving is XL - 7 (-75.0 s, -84.8%), and the largest XL models generally see the deepest cuts (XL - 6 -79.1%, XL - 5 -77.8%, XL - 8 -76.4%). The smallest improvement is S - 8 (-5.6%). Unlike local, even heavy XL models improve dramatically — and in fact gain the most — because remote amplifies both cost factors that schema-view reduces: every schema/metadata round-trip pays network latency, and every byte of schema/metadata pays wire-transfer time.

Models tree initial load

iModel schema-context (s) schema-view (s) Δ (s) Δ (%)
S - 1 1.494 1.171 -0.323 -21.6%
S - 2 1.433 1.026 -0.407 -28.4%
S - 3 1.412 1.395 -0.017 -1.2%
S - 4 1.483 1.017 -0.466 -31.4%
S - 5 1.391 1.389 -0.002 -0.1%
S - 6 1.419 1.040 -0.379 -26.7%
S - 7 1.395 1.029 -0.366 -26.2%
S - 8 1.349 1.105 -0.244 -18.1%
M - 1 1.445 1.032 -0.413 -28.6%
M - 2 1.450 1.266 -0.184 -12.7%
M - 3 1.394 1.320 -0.074 -5.3%
M - 4 1.461 1.258 -0.203 -13.9%
M - 5 1.469 1.646 +0.177 +12.0%
M - 6 1.413 1.021 -0.392 -27.7%
M - 7 1.448 1.009 -0.439 -30.3%
M - 8 1.474 1.243 -0.231 -15.7%
M - 9 1.488 3.982 +2.494 +167.6%
M - 10 1.459 1.045 -0.414 -28.4%
M - 11 1.449 1.025 -0.424 -29.3%
M - 12 1.464 1.031 -0.433 -29.6%
M - 13 1.576 1.023 -0.553 -35.1%
M - 14 1.463 1.024 -0.439 -30.0%
M - 15 0.817 1.731 +0.914 +111.9%
L - 1 1.519 3.221 +1.702 +112.0%
L - 2 1.403 2.655 +1.252 +89.2%
L - 3 1.363 1.313 -0.050 -3.7%
L - 4 1.403 1.840 +0.437 +31.1%
L - 5 1.447 1.893 +0.446 +30.8%
L - 6 1.442 1.023 -0.419 -29.1%
L - 7 1.410 2.436 +1.026 +72.8%
L - 8 1.392 2.278 +0.886 +63.6%
L - 9 0.849 3.266 +2.417 +284.7%
L - 10 0.844 1.775 +0.931 +110.3%
XL - 1 1.493 6.011 +4.518 +302.6%
XL - 2 1.723 3.450 +1.727 +100.2%
XL - 3 1.566 2.140 +0.574 +36.7%
XL - 4 6.768 8.170 +1.402 +20.7%
XL - 5 1.478 1.165 -0.313 -21.2%
XL - 6 1.472 1.033 -0.439 -29.8%
XL - 7 1.488 2.119 +0.631 +42.4%
XL - 8 1.488 1.587 +0.099 +6.7%
XL - 9 1.441 3.047 +1.606 +111.5%

Summary: Mixed result, aggregate up from 64.64 s to 80.25 s (+24.2%), split 24 faster / 18 slower. schema-context is remarkably flat at ~1.4 s for almost every model — the remote path is dominated by a fixed network-latency floor that swamps the actual query work. schema-view pushes the light models below that floor (~1.0 s, consistently -25 to -35%: M - 13 -35.1%, S - 4 -31.4%, M - 7/M - 14/XL - 6 ~-30%) but regresses on the models that have large schemas, which aren't necessary for the tested functionality, but are still retrieved with SchemaView: XL - 1 +4.52 s, M - 9 +2.49 s, L - 9 +2.42 s, XL - 2 +1.73 s, L - 1 +1.70 s, XL - 9 +1.61 s.

Models tree first branch

iModel schema-context (s) schema-view (s) Δ (s) Δ (%)
S - 1 3.301 1.855 -1.446 -43.8%
S - 2 2.362 1.721 -0.641 -27.1%
S - 3 2.990 2.057 -0.933 -31.2%
S - 4 2.306 1.704 -0.602 -26.1%
S - 5 2.928 1.840 -1.088 -37.2%
S - 6 2.234 1.773 -0.461 -20.6%
S - 7 2.275 1.708 -0.567 -24.9%
S - 8 3.964 1.742 -2.222 -56.1%
M - 1 2.538 1.927 -0.611 -24.1%
M - 2 3.474 1.882 -1.592 -45.8%
M - 3 3.708 2.051 -1.657 -44.7%
M - 4 2.908 2.789 -0.119 -4.1%
M - 5 2.880 2.847 -0.033 -1.1%
M - 6 2.385 1.816 -0.569 -23.9%
M - 7 2.487 1.773 -0.714 -28.7%
M - 8 4.167 1.895 -2.272 -54.5%
M - 9 5.210 4.894 -0.316 -6.1%
M - 10 2.439 1.782 -0.657 -26.9%
M - 11 2.317 1.728 -0.589 -25.4%
M - 12 2.321 1.764 -0.557 -24.0%
M - 13 2.425 1.803 -0.622 -25.6%
M - 14 2.346 1.710 -0.636 -27.1%
M - 15 1.518 1.937 +0.419 +27.6%
L - 1 9.931 21.833 +11.902 +119.8%
L - 2 5.435 5.106 -0.329 -6.1%
L - 3 2.669 2.078 -0.591 -22.1%
L - 4 3.618 3.848 +0.230 +6.4%
L - 5 4.359 2.333 -2.026 -46.5%
L - 6 2.354 1.830 -0.524 -22.3%
L - 7 4.891 5.418 +0.527 +10.8%
L - 8 2.683 3.173 +0.490 +18.3%
L - 9 3.877 5.540 +1.663 +42.9%
L - 10 4.500 3.879 -0.621 -13.8%
XL - 1 6.978 9.566 +2.588 +37.1%
XL - 2 7.951 8.259 +0.308 +3.9%
XL - 3 1.550 1.659 +0.109 +7.0%
XL - 4 9.778 8.409 -1.369 -14.0%
XL - 5 2.327 1.938 -0.389 -16.7%
XL - 6 22.425 22.583 +0.158 +0.7%
XL - 7 1.506 1.645 +0.139 +9.2%
XL - 8 3.047 2.162 -0.885 -29.0%
XL - 9 8.177 6.541 -1.636 -20.0%

Summary: Net win for schema-view — aggregate down from 173.54 s to 164.80 s (-5.0%, or -12.6% excluding the dominant L - 1 outlier), split 31 faster / 11 slower. Almost every S/M model improves 20–56% (S - 8 -56.1%, M - 8 -54.5%, M - 2/M - 3 ~-45%), and several heavy models also gain (XL - 9 -20.0%, XL - 8 -29.0%, XL - 4 -14.0%, L - 5 -46.5%). Regressions are concentrated in a few large models, dominated by L - 1 +11.90 s (+119.8%); the next-largest are XL - 1 +2.59 s and L - 9 +1.66 s. XL - 6, the single most expensive case at ~22 s, is essentially flat (+0.7%).

Overall

Against the remote backend the content-descriptor suite is a decisive schema-view win (-66.5%, all 43 cases faster) because remote amplifies every schema/metadata round-trip that schema-view eliminates. The tree suites are more nuanced on a min-of-all-runs basis: Models tree first branch is a net win (-5.0%, 31 of 42 faster, -12.6% excluding the L - 1 outlier), while Models tree initial load regresses overall (+24.2%, 24 of 42 faster). The initial-load regression is structural: remote schema-context sits on a ~1.4 s network-latency floor that hides query cost, so the light models that schema-view speeds up still land ~1.0 s while the heavy, real-work models (XL - 1, M - 9, L - 9) expose the added SchemaView cost as multi-second regressions. Net: schema-view is clearly better for content descriptors and broadly favorable for first-branch navigation, but initial-load on heavier models needs the same follow-up flagged in the local results.

@grigasp

grigasp commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

SchemaContext vs SchemaView — remote comparison

Tests

SchemaContext

  const schemaContext = connection.schemaContext;
  const schema = await schemaContext.getSchema(new SchemaKey("BisCore"));
  await schema?.getEntityClass("Subject");
  await schema?.getEntityClass("PhysicalModel");
  await schema?.getEntityClass("SpatialCategory");
  await schema?.getEntityClass("GeometricElement3d");

SchemaView

  const schemaView = await connection.getSchemaView();
  schemaView.findClass("BisCore.Subject");
  schemaView.findClass("BisCore.PhysicalModel");
  schemaView.findClass("BisCore.SpatialCategory");
  schemaView.findClass("BisCore.GeometricElement3d");

Results

iModel SchemaContext (s) SchemaView (s) Δ (s) Δ (%)
S - 1 0.937 0.471 -0.466 -49.7%
S - 2 0.993 0.285 -0.708 -71.3%
S - 3 0.973 0.720 -0.253 -26.0%
S - 4 0.877 0.286 -0.591 -67.4%
S - 5 0.983 0.718 -0.265 -27.0%
S - 6 0.913 0.298 -0.615 -67.4%
S - 7 0.920 0.280 -0.640 -69.6%
S - 8 0.967 0.358 -0.609 -63.0%
M - 1 0.889 0.294 -0.595 -66.9%
M - 2 1.088 0.497 -0.591 -54.3%
M - 3 0.876 0.615 -0.261 -29.8%
M - 4 0.885 0.507 -0.378 -42.7%
M - 5 0.801 1.180 +0.379 +47.3%
M - 6 0.870 0.292 -0.578 -66.4%
M - 7 0.955 0.281 -0.674 -70.6%
M - 8 0.955 0.437 -0.518 -54.2%
M - 9 0.916 3.669 +2.753 +300.5%
M - 10 1.071 0.271 -0.800 -74.7%
M - 11 0.939 0.277 -0.662 -70.5%
M - 12 0.921 0.280 -0.641 -69.6%
M - 13 0.876 0.275 -0.601 -68.6%
M - 14 0.945 0.292 -0.653 -69.1%
M - 15 0.455 1.843 +1.388 +305.1%
L - 1 0.986 2.639 +1.653 +167.6%
L - 2 1.022 2.121 +1.099 +107.5%
L - 3 0.972 0.277 -0.695 -71.5%
L - 4 0.969 1.324 +0.355 +36.6%
L - 5 0.936 1.256 +0.320 +34.2%
L - 6 0.955 0.269 -0.686 -71.8%
L - 7 0.881 2.316 +1.435 +162.9%
L - 8 0.962 1.952 +0.990 +102.9%
L - 9 0.642 4.163 +3.521 +548.4%
L - 10 0.453 1.843 +1.390 +306.8%
XL - 1 0.973 6.593 +5.620 +577.6%
XL - 2 0.967 2.926 +1.959 +202.6%
XL - 3 0.887 2.262 +1.375 +155.0%
XL - 4 1.102 4.158 +3.056 +277.3%
XL - 5 0.999 0.433 -0.566 -56.7%
XL - 6 0.971 0.276 -0.695 -71.6%
XL - 7 0.906 2.244 +1.338 +147.7%
XL - 8 0.969 0.999 +0.030 +3.1%
XL - 9 0.944 2.931 +1.987 +210.5%

Summary

  • Aggregate: 38.50 s → 55.41 s (+43.9%), split 24 faster / 18 slower.
  • Strongly bimodal, driven by the size of each iModel's schemas. SchemaContext only pulls the schema information that was actually requested (a small amount), so it stays flat at ~0.9 s across every model. SchemaView instead pulls all schema information up front, so it is much faster when the schemas are small but much slower when an iModel carries large schemas.
    • Wins (small schemas): light models drop to ~0.27–0.30 s (−65% to −75%). Biggest: M - 10 −0.800 s (−74.7%), S - 2 −0.708 s (−71.3%), L - 3 −0.695 s (−71.5%), XL - 6 −0.695 s (−71.6%).
    • Regressions (large schemas): models with huge schemas regress hard because SchemaView loads everything — XL - 1 +5.620 s (+577.6%), L - 9 +3.521 s (+548.4%), XL - 4 +3.056 s (+277.3%), M - 9 +2.753 s (+300.5%), XL - 9 +1.987 s, XL - 2 +1.959 s.

@grigasp

grigasp commented Jun 19, 2026

Copy link
Copy Markdown
Member Author

To conclude, as much as I'd like to move forward with SchemaView, I think the performance regressions in "Models tree initial load" tests is a showstopper, especially in the light of https://github.com/iTwin/platform-bentley-community/issues/362.

cc @rschili

@rschili

rschili commented Jun 19, 2026

Copy link
Copy Markdown

To conclude, as much as I'd like to move forward with SchemaView, I think the performance regressions in "Models tree initial load" tests is a showstopper, especially in the light of iTwin/platform-bentley-community#362.

I see.
This makes me eager to come up with an iterative improvement on SchemaView to make it improve this particular scenario. I am already prototyping something.

That said, there is also always the option of using ECSql. I would not recommend going for ECSql for everything, but if this is an isolated area/scenario in your code where it is an option, and you only need a few queries - it should work nicely. Do you want to explore that?

You gave me food for thought about SchemaView anyways, since it performs so well in some scenarios, I kind of want to improve it no matter what you end up choosing.

@rschili

rschili commented Jun 21, 2026

Copy link
Copy Markdown

I had a look at how this branch consumes getSchemaView() and changed SchemaView so there now is a subset/incremental path. Context + full design is in iTwin/itwinjs-core#9431 (two fixes in there: a cheap PRAGMA schema_token for cache invalidation, and the new schema filter). A quick summary of what's relevant for core-interop:

Filter/Subset: IModelDb.getSchemaView({ schemas: [...] }) returns an accumulating view. It fetches only the requested schemas plus their references (one PRAGMA schema_view_fragment blob), merged in place into the same SchemaView instance. Calling it again with more names extends that same instance - indices stay stable, so any view reference you've captured just grows. No args = today's full-view behavior, unchanged.

How your adapter can consume it: your ECSchemaProvider.getSchema(name) is already async, which is the natural seam. On a miss it can await imodel.getSchemaView({ schemas: [name] }) and then wrap as you do today. Because requesting a schema also pulls everything it references, your synchronous is() / baseClass walking stays correct: a class's full ancestor chain is always loaded once the class's own schema is. The createEC*FromSchemaView doesn't need to change - just stop eagerly awaiting a full view at creation and limit it to maybe "BisCore" at first.

Two things to watch:

  1. Don't call getSchemaView() per is-check. It's cheap when everything requested is already loaded (a synchronous loaded-name Set gate, no I/O) but it's not zero-cost - it's still an async call with a manifest/lookup check. For your classDerivesFrom path (potentially ~1M calls), hydrate the schemas you need once and then do the sync is() work against the captured view. Try not to put a getSchemaView call inside the hot loop.

  2. getDerivedClasses() now has the known drawback from the past. The model-tree hot path is upward-only (classDerivesFrom + per-class selection), so it's unaffected. But if any feature needs all subclasses of a base across the iModel, do a single up-front await imodel.getSchemaView() or it will only return derived classes that are already loaded.

My PR is still just a draft, I need to polish it some more. IModelConnection does not have the filter yet, I want to nail it on the backend implementation first. But I expect I can get this done within the week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Accessing ECClass information is slow when they come from large ECSchemas

2 participants