# Persistent Database Index Optimization in C

> ## Cursor read-ahead buffering

> Navigating index structures can require accessing many pages of index “leaf” nodes. For example an application performing a sequential traversal of a disk-based B-Tree index will perform a blocking read access for each index page. This can have a significant performance cost. To reduce the number of costly read operations, the runtime reads several index pages into an internal cursor buffer. The number of keys taken from a leaf of a B-Tree page on each access is determined by the value of the database parameter `btree_cursor_read_ahead_size` in the `mco_db_params_t` passed into `mco_db_open_dev()`. This value can be changed but cannot be larger than the value of configuration parameter `MCO_CFG_CURSOR_BUF_SIZE` which has the default value of 10.

> > Note that to change configuration parameters like `MCO_CFG_CURSOR_BUF_SIZE` requires an eXtremeDB source code license.

> ## Block Allocation

> eXtremeDB provides a block allocator to facilitate objects’ locality of references, i.e. to assure that a group of objects will be stored in a contiguous block on persistent media. This capability is provided in the form of the generated function `<classname>_set_allocation_block_size()`. The application calls this function within a `READ_WRITE` transaction with a sufficient block size to store a group of objects of the given class. This function provides major performance improvements for persistent objects:

> - It keeps the entire object within the same block, greatly improving the read performance for complex objects
> - It keeps groups of objects that had been added to the database at the same time stored together within the same block, improving the sequential access performance for objects of the same class

> When `<classname>_set_allocation_block_size()` is used, and objects of `classname` are deleted, the space is returned back to the database pool and can be reused for indexes and other objects. But this space will not be reused for objects of the same class because these new objects are allocated by blocks. Thus, deleting objects does not reduce the locality of reference.

> The block allocator works well when objects are not updated, because when a dynamic object is updated it is possible that a part (the variable length part) of the object will be allocated outside the block. To lessen this effect, the runtime always attempts to allocate the entire object on the same page (Disk Manager page) as the object header.

> > Note that database file fragmentation can also be greatly reduced by use of the `file_extension_quantum` element of the `mco_db_params_t` structure used when opening or extending the database (see function `mco_db_open_dev()`) . A non-zero value for `file_extension_quantum` will cause the database runtime to grow the database file by the specified number of bytes as opposed to growing the database file by the page size (typically 4K, 8K, or 16K).