Status: Public Preview — behaviour may change.
What it does
String indexing builds an optimised search structure over a string column so that CONTAINSSTRING and SEARCH can find substrings without scanning the whole dictionary. It never changes a result; if there's no index, the query takes the normal path and just runs slower.
Key facts
- Preview, and Learn marks it as Fabric / Power BI Premium only. It isn't available for SSAS or Azure Analysis Services.
- Needs compatibility level 1707 or later. The upgrade is irreversible, and adding the property in TMDL view in the service triggers it automatically.
- Only
stringcolumns in Import, Dual or Direct Lake tables qualify. Pure DirectQuery tables don't. - Each column takes a
stringIndexingBehavior:auto(the default, built lazily on first qualifying query with a 25-second limit per attempt, held in memory only),full(built on every refresh, persisted),explicit(built only by anindexesrefresh, persisted) oroff. - The
indexesrefresh type is XMLA-only. It's not in the refresh UI or the REST refresh API. - An
explicitindex needs its own transaction after the data refresh has committed. Combine them and the index isn't rebuilt. - There's no property editor. You configure it in TMDL view or over the XMLA endpoint, and there's no customer-facing way to confirm a persisted index exists. You infer it from refresh results, traces and timings.
- Dual and Direct Lake only benefit when the query runs against locally materialised VertiPaq data. DirectQuery fallback and non-materialised columns get no help.
- Import-only incremental refresh is supported; incremental refresh with a real-time DirectQuery partition isn't.
When to use / skip
Use it on one or two big free-text columns (names, descriptions, review text) where users genuinely run substring searches and the first query is visibly slow. Skip it on small or low-cardinality columns; auto already costs you nothing there and persisting an index just adds model size.
Configuration decisions
autoversusfullper column.fullis the recommended persisted option during preview overexplicit.- Which columns earn persistence at all. Each persisted index adds size, refresh CPU and memory.
- Whether you can live with
explicitneeding XMLA and a separate refresh step in your pipeline. - For Direct Lake, whether auto-sync stays on once indexes are persisted.
Gotchas
- A TMSL
createOrReplacereplaces the whole column object. Send onlystringIndexingBehaviorand you strip the other properties off the column. - Index builds are memory-hungry on high-cardinality Unicode columns, and parallel builds on a small capacity will fall over with out-of-memory refresh failures.
- On Direct Lake, persisted indexes lengthen auto-sync, so data lands later than people expect.
- Older client tools may not recognise level 1707 or the new property, which is a real problem if a colleague opens the model in a stale version of Tabular Editor or Desktop.
- Not every string expression or Unicode pattern is eligible. Test on representative queries before you promise anything.
Consultant notes
- Measure before and after on a realistic search workload. If you can't show a first-query improvement, don't pay the refresh cost.
- Preview plus an irreversible compatibility upgrade is a decision for dev first. Don't bump a production model's level for a preview feature without a rollback copy.
- Put the XMLA step in the deployment pipeline up front if you go
explicit, otherwise it gets forgotten and the index quietly never exists. - Watch the capacity memory metrics on the first full refresh after enabling it, not a fortnight later.
Revisit when string indexing reaches general availability or gains a UI.