Documentation Index
Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
Use this file to discover all available pages before exploring further.
What is an Index
An index allows better search performances. When a column is indexed, it allows knowing in which records a given value exists, without having to actually read all records in the column. There are two types of indexes based on their usage:- Unique index: an index that allows to ensure uniqueness of a given value. Used for the key fields of a store.
- Secondary index: an index that allows repetition of the same value in different records. Used “only” for query performance.
- Single column index: an index based on the value of a single column in a store
- Composite index: an index based on the combination of values from several columns in a store
JUST_IN_TIME aggregates provider,
or when project code is written to directly query the stores.
In such cases, additional indexes on other columns or groups of columns may be needed to improve performance.
Key Fields Index
When a store is created with one key field, a unique, single column index is automatically created for that one field. When a store is created with more than one key field, a unique, composite index that encompasses all these key fields is automatically created. The composite key ensures uniqueness in the index and in the store. The following example shows a key comprising three key fields.Index on Individual Columns
If a single column is the key field of a store, it is automatically indexed. But one might also want to index an individual column, even if it is not a key field: indexing allows faster searches when a search is done directly on an indexed column. The following example shows a field called “A”, which isn’t a key field but requires an index for faster searching.indexed() method are
secondary indexes (do not ensure uniqueness).
If a key field needs to be indexed (for example, there are two key fields so a composite index is created,
but one key field is often queried alone), it is also possible to use the indexed() method:
Composite Index
When several columns are frequently queried together, an index that combines these columns can be defined using thewithIndexOn() method, as shown below.
Log Query Plans
When query performance needs to be investigated, the server can be set to log more detailed information about which indexes, if any, are being used. The associated loggeratoti.server.datastore.query (see the logger hierarchy) can be (temporarily) set to the
TRACE (logback) or FINER (jul) level to log such query plans.
The following sample log file output shows that a query has effectively done a table scan for the three columns:
Automatic Indexing
Atoti automatically creates a unique index containing all the key fields. It will also create a secondary index on all fields used in a reference between two stores. For example, ifStore-1 references Store-2 through fields A, B, and C, then a secondary composite index using
A, B, and C is automatically created on Store-1. A unique index on fields A, B, C will also be created for Store-2.
Consequently, when analyzing queries for scans and indexes used, a secondary index lookup may appear to be
performed even if no explicit index for those fields has been created.
This automatic index creation can be overridden by calling dontIndexOwner() on the store reference builder.
Calling dontIndexOwner() will have several effects:
- It will reduce the memory footprint.
- It will speed up commits in the owner store.
- It will slow down the queries on those fields.
- It will slow down the propagation of updates from the target store to the owner store, and hence slow down the commit when committing in the target store.
Store Index Recommendation
Atoti provides a utility that helps create the necessary indexes for a project, based on the actual usage when querying the stores. This utility is available via MBeans, so it must be accessed via a tool which supports them, such as JConsole or jvisualvm. The screenshots provided below use JConsole. After launching JConsole (or an equivalent tool) and connecting to the application, go to the MBeans tab and navigate tocom.activeviam > Datastore > Datastore schema > Operations. The void enableStoreIndexRecommendation()
operation is available there.


Datastore schema MBean, and look for the IndexRecommendations attribute.
If the store index recommendation was not enabled, or if the provided workload did not mandate using indexes on
that store, only an empty array will be displayed.


Index Memory Management
Datastore indexes significantly improve query performance but come with a high memory cost. Two complementary options are offered to manage it: compressed indexes at build time, and index rebuilding at runtime.Why does index memory usage grow over time
A datastore index consists of a dictionary plus additional arrays:- Unique index: one integer array with the same size as the index dictionary.
- Secondary index: one integer array with the same size as the index dictionary, plus another integer array sized accordingly to the maximum row ID of the partition.
Compress indexes
To reduce the memory footprint of a store’s indexes,.compressIndexes() can be called on the store description
builder. Indexes are then stored in a compressed format, at the cost of additional computation on reads (decompression,
and potentially extra memory accesses when looking up a key).
Compression is disabled by default. It should be enabled only when memory issues are encountered on a store that has
many or large indexes.
Rebuild indexes
Indexes can be rebuilt at runtime to reclaim memory. This process recomputes the index data structures and only includes active (non-deleted) records. As a result, dictionary sizes may shrink, reducing the size of the integer arrays as well. To rebuild all indexes (key, unique, and secondary) for a store:When to rebuild indexes
Rebuilding indexes is not required during normal operation. Consider rebuilding when:- A store has undergone heavy updates or deletions.
- Index memory usage has grown excessively.
- The memory footprint needs to be optimized after loading large amounts of temporary data.