Before you begin
Before reading this page, do the following:- or .
- .
- .
- .
- .
- Review the best practices.
Create a secondary index
To add a secondary index to a table do one of the following:-
Add an
INDEXclause to the end of a statement.INDEXclauses generally take the following form:
-
Use a statement.
CREATE INDEXstatements generally take the following form:
For an example, see Example.
- If you do not specify a name for an index, CockroachDB will generate a name. - The notation for referring to an
index is
{table_name}@{index_name}.
Best practices
Here are some best practices for creating and using secondary indexes.Index contents
-
Index all columns that you plan to use for or data.
An index that stores all the columns needed by a query is also known as a covering index for that query. When a query has a covering index, CockroachDB can use that index directly instead of doing an “index join” with the primary index, which is likely to be slower.
CockroachDB (i.e., values listed in a ) into an index, which allows it to perform a finite number of sequential scans. In a
WHEREclause withnconstrained columns you can filter the firstn-1columns either on a single constant value using the operator=or a list of constant values using the operatorIN. You can filter columnnagainst a range of values using any of the operators!=,<,>, orNOT IN. Columns with a higher cardinality (higher number of distinct values) should be placed in the index before columns with a lower cardinality. If the cardinality of the columns you wish to add to the index are similar, test multiple column arrangements in a non-production environment to determine the most performant arrangement. - If you need to index the result of a function applied to one or more columns of a single table, use the function to create a and index the column.
- Avoid indexing on sequential keys (e.g., columns). Writes to indexes with sequential keys can result in range that negatively affect performance. Instead, use or . If you are working with a table that must be indexed on sequential keys, use . For details about the mechanics and performance improvements of hash-sharded indexes in CockroachDB, see our Hash Sharded Indexes Unlock Linear Scaling for Sequential Workloads blog post.
-
Use a to store columns of data that you want returned by common queries, but that you do not plan to use in query filters.
The
STORINGclause specifies columns that are not part of the index key but should be stored in the index. If a column is specified in a query, and the column is neither indexed nor stored in an index, CockroachDB may either perform a full scan or perform an if a suitable secondary index exists. However, if the optimizer determines that the index join is too expensive, then CockroachDB will perform a full table scan. For an example, see Example. - Review the , such as partial and inverted indexes, and decide if you need to create a specialized index instead of a standard index.
-
Avoid creating secondary indexes that you do not need.
- Queries can benefit from an index even if they only filter a prefix of its columns. For example, if you create an index of columns
(A, B, C), queries filtering(A)or(A, B)can use the index, so you don’t need to also index(A). - If you need to , and you do not plan to filter queries on the existing primary key column(s), do not use because it creates a secondary index from an existing primary key. Instead, use , which does not create a secondary index.
- Queries can benefit from an index even if they only filter a prefix of its columns. For example, if you create an index of columns
Index management
- Limit creation and deletion of secondary indexes to off-peak hours. Performance impacts are likely if done during peak business hours.
-
Do not create indexes as the
rootuser. Instead, create indexes as a , with fewer privileges, following . This will likely be the same user that created the table to which the index belongs. -
Drop unused indexes whenever possible.
- In the DB Console, visit the and check databases and tables for to drop unused indexes.
-
To understand usage statistics for an index, query the table.
To get more detailed information about the table and index names, run a join query against
crdb_internal.index_usage_statisticsandcrdb_internal.table_indexes. For an example, see .
- Use a or the instead of a to execute .
- Review the . CockroachDB . Cockroach Labs recommends that you perform schema changes outside explicit transactions. When a database manages transactions on your behalf, include one schema change operation per transaction.
Example
Suppose you want the MovR application to display all of the bikes available to the users of the MovR platform. Recall that thevehicles table that you created in stores rows of data for each vehicle registered with MovR. Your application will need to read any data about vehicles into the application’s persistence layer from this table. To display available bikes, the reads will need to filter on the available and type columns.
Open max_init.sql, and, under the CREATE TABLE statement for the vehicles table, add a CREATE INDEX statement for an index on the type and available columns of the vehicles table:
type_available_idx, on the vehicles table.
The MovR app might also need to display the vehicle’s location and ID, but the app will not be filtering or sorting on those values. If any of the columns referenced in or returned by a query are not in a primary or secondary index key, CockroachDB will need to perform to find the value. Full table scans can be costly, and should be avoided whenever possible.
To help avoid unnecessary full table scans, add a STORING clause to the index:
last_location, which will improve the performance of reads from the vehicles table that return type, available, id, and last_location values and do not filter or sort on the last_location column.
The max_init.sql file should now look similar to the following:
dbinit.sql file as the root user:
max_init.sql and abbey_init.sql files:
vehicles table, issue a statement:
SHOW statement displays the names and columns of the two indexes on the table (i.e., vehicles_pkey and type_available_idx).
The last_location column’s storing value is true in the type_available_idx index, and is therefore not sorted. The primary key column id is implicit in the index, meaning the id column is implicitly indexed in type_available_idx.
To see an index definition, use a statement on the table that contains the index:

