--- layout: default description: Learn how to use different indexes efficiently by going through theArangoDB Performance Course --- Working with Indexes ==================== Learn how to use different indexes efficiently by going through the [ArangoDB Performance Course](https://www.arangodb.com/arangodb-performance-course/){:target="_blank"}. Index Identifiers and Handles ----------------------------- An *index handle* uniquely identifies an index in the database. It is a string and consists of the collection name and an *index identifier* separated by a `/`. The index identifier part is a numeric value that is auto-generated by ArangoDB. A specific index of a collection can be accessed using its *index handle* or *index identifier* as follows: ```js db.collection.index(""); db.collection.index(""); db._index(""); ``` For example: Assume that the index handle, which is stored in the `_id` attribute of the index, is `demo/362549736` and the index was created in a collection named `demo`. Then this index can be accessed as: ```js db.demo.index("demo/362549736"); ``` Because the index handle is unique within the database, you can leave out the *collection* and use the shortcut: ```js db._index("demo/362549736"); ``` An index may also be looked up by its name. Since names are only unique within a collection, rather than within the database, the lookup must also include the collection name. ```js db._index("demo/primary") db.demo.index("primary") ``` Collection Methods ------------------ ### Listing all indexes of a collection returns information about the indexes `getIndexes()` Returns an array of all indexes defined for the collection. Since ArangoDB 3.4, `indexes()` is an alias for `getIndexes()`. Note that `_key` implicitly has an index assigned to it. {% arangoshexample examplevar="examplevar" script="script" result="result" %} @startDocuBlockInline collectionGetIndexes @EXAMPLE_ARANGOSH_OUTPUT{collectionGetIndexes} ~db._create("test"); ~db.test.ensureUniqueSkiplist("skiplistAttribute"); ~db.test.ensureUniqueSkiplist("skiplistUniqueAttribute"); |~db.test.ensureHashIndex("hashListAttribute", "hashListSecondAttribute.subAttribute"); db.test.getIndexes(); ~db._drop("test"); @END_EXAMPLE_ARANGOSH_OUTPUT @endDocuBlock collectionGetIndexes {% endarangoshexample %} {% include arangoshexample.html id=examplevar script=script result=result %} ### Creating an index Indexes should be created using the general method *ensureIndex*. This method obsoletes the specialized index-specific methods *ensureHashIndex*, *ensureSkiplist*, *ensureUniqueConstraint* etc. ensures that an index exists `collection.ensureIndex(index-description)` Ensures that an index according to the *index-description* exists. A new index will be created if none exists with the given description. The *index-description* must contain at least a *type* attribute. Other attributes may be necessary, depending on the index type. **type** can be one of the following values: - *hash*: hash index - *skiplist*: skiplist index - *fulltext*: fulltext index - *geo*: geo index, with _one_ or _two_ attributes **name** can be a string. Index names are subject to the same character restrictions as collection names. If omitted, a name will be auto-generated so that it is unique with respect to the collection, e.g. `idx_832910498`. **sparse** can be *true* or *false*. For *hash*, and *skiplist* the sparsity can be controlled, *fulltext* and *geo* are [sparse](indexing-which-index.html) by definition. **unique** can be *true* or *false* and is supported by *hash* or *skiplist* Calling this method returns an index object. Whether or not the index object existed before the call is indicated in the return attribute *isNewlyCreated*. **deduplicate** can be *true* or *false* and is supported by array indexes of type *hash* or *skiplist*. It controls whether inserting duplicate index values from the same document into a unique array index will lead to a unique constraint error or not. The default value is *true*, so only a single instance of each non-unique index value will be inserted into the index per document. Trying to insert a value into the index that already exists in the index will always fail, regardless of the value of this attribute. **Examples** {% arangoshexample examplevar="examplevar" script="script" result="result" %} @startDocuBlockInline collectionEnsureIndex @EXAMPLE_ARANGOSH_OUTPUT{collectionEnsureIndex} ~db._create("test"); db.test.ensureIndex({ type: "hash", fields: [ "a" ], sparse: true }); db.test.ensureIndex({ type: "hash", fields: [ "a", "b" ], unique: true }); ~db._drop("test"); @END_EXAMPLE_ARANGOSH_OUTPUT @endDocuBlock collectionEnsureIndex {% endarangoshexample %} {% include arangoshexample.html id=examplevar script=script result=result %} ### Dropping an index via a collection handle drops an index `collection.dropIndex(index)` Drops the index. If the index does not exist, then *false* is returned. If the index existed and was dropped, then *true* is returned. Note that you cannot drop some special indexes (e.g. the primary index of a collection or the edge index of an edge collection). `collection.dropIndex(index-handle)` Same as above. Instead of an index an index handle can be given. {% arangoshexample examplevar="examplevar" script="script" result="result" %} @startDocuBlockInline col_dropIndex @EXAMPLE_ARANGOSH_OUTPUT{col_dropIndex} ~db._create("example"); db.example.ensureSkiplist("a", "b"); var indexInfo = db.example.getIndexes(); indexInfo; db.example.dropIndex(indexInfo[0]) db.example.dropIndex(indexInfo[1].id) indexInfo = db.example.getIndexes(); ~db._drop("example"); @END_EXAMPLE_ARANGOSH_OUTPUT @endDocuBlock col_dropIndex {% endarangoshexample %} {% include arangoshexample.html id=examplevar script=script result=result %} ### Load Indexes into Memory Loads all indexes of this collection into Memory. `collection.loadIndexesIntoMemory()` This function tries to cache all index entries of this collection into the main memory. Therefore it iterates over all indexes of the collection and stores the indexed values, not the entire document data, in memory. All lookups that could be found in the cache are much faster than lookups not stored in the cache so you get a nice performance boost. It is also guaranteed that the cache is consistent with the stored data. For the time being this function is only useful on RocksDB storage engine, as in MMFiles engine all indexes are in memory anyways. On RocksDB this function honors all memory limits, if the indexes you want to load are smaller than your memory limit this function guarantees that most index values are cached. If the index is larger than your memory limit this function will fill up values up to this limit and for the time being there is no way to control which indexes of the collection should have priority over others. {% arangoshexample examplevar="examplevar" script="script" result="result" %} @startDocuBlockInline LoadIndexesIntoMemory @EXAMPLE_ARANGOSH_OUTPUT{loadIndexesIntoMemory} ~db._drop("example"); ~db._createEdgeCollection("example"); db.example.loadIndexesIntoMemory(); ~db._drop("example"); @END_EXAMPLE_ARANGOSH_OUTPUT @endDocuBlock LoadIndexesIntoMemory {% endarangoshexample %} {% include arangoshexample.html id=examplevar script=script result=result %} Database Methods ---------------- ### Fetching an index by handle finds an index `db._index(index-handle)` Returns the index with *index-handle* or null if no such index exists. {% arangoshexample examplevar="examplevar" script="script" result="result" %} @startDocuBlockInline IndexHandle @EXAMPLE_ARANGOSH_OUTPUT{IndexHandle} ~db._create("example"); db.example.ensureIndex({ type: "skiplist", fields: [ "a", "b" ] }); var indexInfo = db.example.getIndexes().map(function(x) { return x.id; }); indexInfo; db._index(indexInfo[0]) db._index(indexInfo[1]) ~db._drop("example"); @END_EXAMPLE_ARANGOSH_OUTPUT @endDocuBlock IndexHandle {% endarangoshexample %} {% include arangoshexample.html id=examplevar script=script result=result %} ### Dropping an index via a database handle drops an index `db._dropIndex(index)` Drops the *index*. If the index does not exist, then *false* is returned. If the index existed and was dropped, then *true* is returned. `db._dropIndex(index-handle)` Drops the index with *index-handle*. {% arangoshexample examplevar="examplevar" script="script" result="result" %} @startDocuBlockInline dropIndex @EXAMPLE_ARANGOSH_OUTPUT{dropIndex} ~db._create("example"); db.example.ensureIndex({ type: "skiplist", fields: [ "a", "b" ] }); var indexInfo = db.example.getIndexes(); indexInfo; db._dropIndex(indexInfo[0]) db._dropIndex(indexInfo[1].id) indexInfo = db.example.getIndexes(); ~db._drop("example"); @END_EXAMPLE_ARANGOSH_OUTPUT @endDocuBlock dropIndex {% endarangoshexample %} {% include arangoshexample.html id=examplevar script=script result=result %} ### Revalidating whether an index is used finds an index So you've created an index, and since its maintainance isn't for free, you definitely want to know whether your query can utilize it. You can use explain to verify whether **skiplists** or **hash indexes** are used (if you omit `colors: false` you will get nice colors in ArangoShell): {% arangoshexample examplevar="examplevar" script="script" result="result" %} @startDocuBlockInline IndexVerify @EXAMPLE_ARANGOSH_OUTPUT{IndexVerify} ~db._create("example"); var explain = require("@arangodb/aql/explainer").explain; db.example.ensureIndex({ type: "skiplist", fields: [ "a", "b" ] }); explain("FOR doc IN example FILTER doc.a < 23 RETURN doc", {colors:false}); ~db._drop("example"); @END_EXAMPLE_ARANGOSH_OUTPUT @endDocuBlock IndexVerify {% endarangoshexample %} {% include arangoshexample.html id=examplevar script=script result=result %}