Vector Indexing
On this page
SingleStore supports vector similarity scoring and you can use this to find the exact set of k nearest neighbors of a query vector, as described in Working with Vector Data.
If you have very large data sets and/or high concurrency requirements for a nearest-neighbor search, exact kNN search may not be efficient enough.
There is an accuracy vs.
If you have nearest neighbor queries that do not have any selective filters associated with them, and large sets of vectors, use an ANN search.
Some sample cases for using ANN search are:
-
Semantic Search of Text based on vectors from large language models (LLMs)
-
Retrieval-Augmented Generation (RAG) to enable focused, high-quality results for text generation based on LLMs within specific knowledge areas
This topic explains how to create a vector index to enable ANN search, how to write queries that will use the index, and how to determine if the index is being used.
Syntax
The syntax for a vector index has to adhere to the following rules:
-
Vector indexes can only be built on columnstore tables.
-
A vector index must be built on a single column.
-
Column type is restricted to Vector Type
(<N>, [F32]), where<N>is the number of dimensions.Currently, the only supported element type is F32.
Similarity Metrics
Two similarity functions are available for creating and searching vector indexes in SingleStore: DOT_ and EUCLICEAN_.
DOT_: Calculates the cosine similarity metric when used with vectors normalized to length 1.DOT_ on vectors normalized to length 1 range from -1 to 1; values closer to 1 indicate that the vectors are similar, whearas values closer to -1 indicate that the vectors are less similar.
EUCLIDEAN_: Calculates the Euclidean distance between two vectors.EUCLIDEAN_ range from 0 to infinity; values closer to 0 indicate that the vectors are similar, values closer to infinity indicate that vectors are less similar.
Remarks
-
Search queries must use the same metric used in the creation of a vector index to use that index.
That is, a query that uses DOT_can only use a vector index created withPRODUCT DOT_.PRODUCT -
Vectors must be normalized to length 1 before using the
DOT_function to obtain the cosine similarity metric.PRODUCT SingleStore recommends vectors are normalized to length 1 before they are saved to the database. Many models that produce vector embeddings produce vectors normalized to length 1. In this case, it is not necessary to normalize the vectors again. -
Using
EUCLIDEAN_over vectors which have been normalized to length 1 may result in poor recall because normalization causes the magnitude information present in the original vectors to be lost.DISTANCE
Creating a Vector Index
A vector index can be created using the CREATE TABLE command:
CREATE TABLE <table_name> (<column_definitions>, VECTOR {INDEX|KEY } [<index_name>] (<column>) [INDEX_OPTIONS '<json>']);
Alternatively, a vector index may be added using the ALTER TABLE command:
ALTER TABLE <table_name> ADD VECTOR {INDEX|KEY } [<index_name>] (<column>) [INDEX_OPTIONS '<json>'];
Multiple vector indexes can be created on the same table or even on the same column.
A vector index may be dropped with the ALTER TABLE command:
ALTER TABLE <table_name> DROP INDEX <index_name>;ORDROP INDEX <index_name> ON <table_name>;
Searching a Vector Index
A vector search query to find k ANNs can be done with standard SQL:
SELECT <columns>,DOT_PRODUCT | EUCLICEAN_DISTANCE (<table_name>.v, @query_vector) AS distanceFROM <table_name>WHERE <pre-filters>ORDER BY distance [USE {INDEX|KEY} ([<index_name>])][SEARCH_OPTIONS [=] '<json>'] [{DESC|ASC}]LIMIT k;
Infix syntax is available.
-
<*> for
DOT_PRODUCT -
<-> for
EUCLICEAN_DISTNCE
SELECT <columns>,<table_name>.v {<*>|<->} @query_vector AS distanceFROM <table_name>WHERE <pre-filters>ORDER BY distance [USE {INDEX|KEY} ([<index_name>])][SEARCH_OPTIONS [=] '<json>'] [{DESC|ASC}]LIMIT k;
Important:
-
For
DOT_(<*>), higher values indicate higher vector similarity; use descending (PRODUCT DESC) order in theORDER BYclause. -
For
EUCLIDEAN_(<->), lower values indicate smaller distance between values; use ascending (DISTANCE ASC) theORDER BYclause, which is the default. -
Search queries must use the same distance metric (
DOT_orPRODUCT EUCLIDEAN_) as used in the vector index in order to utilize that vector index.DISTANCE -
The query vector (
@query_in the syntax above) must be a runtime constant.vector
Index Options
A JSON config string can be used with INDEX_ to specify the vector index algorithm and its parameters to use.SEARCH_.
Below are the generic INDEX_ and SEARCH_.INDEX_) and index searching parameters (SEARCH_) can be used with all index types.
-
Index building parameters
-
index_
type: index type to use. Must be one of AUTO, FLAT, IVF_ FLAT, IVF_ PQ, IVF_ PQFS, HNSW_ FLAT, HNSW_ PQ. The default is AUTO. SingleStore recommends IVF_ PQFS and HNSW_ FLAT. -
metric_
type: distance metric. Either EUCLIDEAN_orDISTANCE DOT_.PRODUCT The default is DOT_.PRODUCT
-
-
Search parameters
-
k: number of rows outputted by vector index scan.
k must be >= limit, where limit is from ORDER BY … LIMITclause.The default is the limit.
-
Index Hints
When there are multiple vector indices available or when you want to disable any available vector index, the index hint [USE {INDEX|KEY} ([<index_ can be used to specify a specific index to use or to disable the use of an index.
Specify the exact index you want to use as <index_ or omit the <index_ part, i. USE {INDEX|KEY} () to disable ANN search.
Index Types and Parameters
The following index types and parameters are supported.
All index search parameters can also be specified as index building parameters in INDEX_.INDEX_, that value will be used as the default value for searches using that index so you do not need to specify those values each time you use that index.
Note
SingleStore recommends using the IVF_
AUTO
AUTO automatically selects the vector index algorithm and parameters.
AUTO currently behaves the same as IVF_
FLAT
FLAT does not use an index.
IVF_ FLAT
When using basic Inverted File Index (IVF), vectors are clustered into nlist clusters and search is done by searching only nprobe nearest clusters.nlist parameter controls the number of centroids generated by k-means clustering.nprobe cannot be greater than nlist.
-
Index building parameters:
-
nlist: number of inverted lists (number of clusters) created during index build.
1 <= nlist <= 65536. Default to 128. -
nprobe: number of probes at query time.
1 <= nprobe <= 65536. Default to 8.
-
-
Search parameters:
-
nprobe
-
IVF_ PQ
Inverted file index with residual vectors PQ-encoded.nlist clusters and search is done by searching only nprobe nearest clusters.nlist parameter controls the number of centroids generated by k-means clustering.nprobe cannot be greater than nlist.
-
Index building parameters:
-
nlist: number of inverted lists (number of clusters) created during index build.
1 <= nlist <= 65536. Default to 128. -
m: number of subquantizers used in product quantization.
Dimensions % m must equal 0. Default to 32. -
nbits: number of bits per quantization index.
1 <= nbits <= 16. Default to 8. -
nprobe: number of probes at query time.
1 <= nprobe <= 65536. Default to 8.
-
-
Search parameters:
-
nprobe
-
IVF_ PQFS
IVF_nlist clusters and search is done by searching only nprobe nearest clusters.nlist parameter controls the number of centroids generated by k-means clustering.nprobe cannot be greater than nlist.
-
Index building parameters:
-
nlist: number of inverted lists (number of clusters) created during index build.
1 <= nlist <= 65536. Default to 128. -
m: number of subquantizers used in product quantization.
Dimensions % m must equal 0. Default to 32. -
nprobe: number of probes at query time.
1 <= nprobe <= 65536. Default to 8.
-
-
Search parameters:
-
nprobe
-
HNSW_ FLAT
Basic Hierarchical Navigable Small World (HNSW) index.
-
Index building parameters:
-
M: number of neighbors.
1 <= M <= 2048. Default to 30. -
efConstruction: expansion factor at construction time.
1 <= efConstruction. Default to 40. -
ef: expansion factor at search time.
1<= ef. Default to 16.
-
-
Search parameters:
-
ef
-
HNSW_ PQ
HNSW with vectors PQ-encoded.
-
Index building parameters:
-
M: number of neighbors.
1 <= M <= 2048. Default to 30. -
efConstruction: expansion factor at construction time.
1 <= efConstruction. Default to 40. -
m: number of sub-quantizers.
dimensions % m must equal 0. Default to 32. -
nbits: number of bits per quantization index.
1 <= nbits <= 16. Default to 8. -
ef: expansion factor at search time.
1 <= ef. Default to 16.
-
-
Search parameters: ef: expansion factor at search time.
1 <= ef. Default to 16. -
ef
-
Vector Index Architecture
When a vector index is built, a table-level index is created for the vector column.
Refer to Managing Columnstore Segments for more information about segments.
Vector Index Cache
When a vector search query is run, the relevant per-segment indexes used by the query are fetched from disk and stored in an in-memory cache.
The size of the vector index cache can be tuned with the max_ engine variable which controls the percent of total memory used for the vector cache.max_ is a read-only variable which provides a convenient way to check the memory usage of the vector index cache in MB.
|
|
Specifies the maximum percentage of total available memory to be used by the vector index cache. |
|
|
The maximum amount of memory that can be used by the vector index cache (in MB). |
Note
For customers who have upgraded to version 9.max_ to 40% (the default value in version 9.
Refer to Sync Variables Lists for default values.
Remarks
-
Since the vector index cache is of limited size, one or more per-segment indexes that are not in use may be evicted from the cache when another index is loaded into the cache.
If there are not enough evictable per-segment indexes, the engine reports an out of memory (OOM) error message. -
If the value of
max_is modified in a way that reduces the size of the vector index cache, the following occurs:vector_ index_ cache_ memory_ percent -
The resize succeeds if the new percentage is a legal value.
-
The next time the cache is used, for example when a query is run that uses a vector index, the engine evicts per-segment indexes that are not in use to reduce the size of the cache until the cache is smaller than the new limit.
-
If there are not enough evictable per-segment indexes, the engine reports OOM.
-
-
Refer to Memory Errors for more information.
Vector Index Merger
The vector index merger combines per-segment vector indexes to create a cross-segment vector index.
The vector index merger automatically runs in the background to continuously improve search performance.
OPTIMIZE TABLE <table_name> VECTOR_INDEX <index_name>;
In addition, the vector index merger is also run when the OPTIMIZE TABLE . command shown below is run.
OPTIMIZE TABLE <table_name> FULL;
Vector Index Fallback to Full Table Scan
Queries that use Approximate Nearest Neighbor (ANN) indexed vector search require a LIMIT clause to specify the number of results to be returned.WHERE clause, these filters may reduce the number of results returned because they are applied after the indexed search.
If the engine detects that an indexed vector search followed by the filters yields fewer than LIMIT rows, the engine falls back to a full table scan to ensure sufficient rows are produced.LIMIT) is returned, provided there are at least LIMIT valid results in the dataset.
The fallback mechanism can be disabled by setting the engine variable vector_ to false.
Tracking Vector Index Memory Use
Use the VECTOR_
The VECTOR_ information schema view shows the amount of memory and disk used by each vector index.
Example output from the VECTOR_ information schema view is shown below.
SELECT * FROM INFORMATION_SCHEMA.VECTOR_INDEX;
+---------------+------------+---------+------------+-------------------+------------------------+-----------------+----------------------+
| DATABASE_NAME | TABLE_NAME | NODE_ID | INDEX_TYPE | MEMORY_SIZE_BYTES | INDEX_CHUNKS_IN_MEMORY | DISK_SIZE_BYTES | INDEX_CHUNKS_ON_DISK |
+---------------+------------+---------+------------+-------------------+------------------------+-----------------+----------------------+
| test | ann_test | 2 | HnswFlat | 138460664 | 1 | 276962270 | 3 |
| test | ann_test | 2 | IvfPqfs | 10488248 | 3 | 9557524 | 3 |
+---------------+------------+---------+------------+-------------------+------------------------+-----------------+----------------------+In this output, there are two indexes on the table ann_.
The total memory used by all vector indexes can be viewed by using the SHOW STATUS EXTENDED command as shown below.
SHOW STATUS EXTENDED LIKE 'alloc_vector_index'
+--------------------+-------------------+
| Variable_name | Value |
+--------------------+-------------------+
| alloc_vector_index | 5.942 (+5.942) MB |
+--------------------+-------------------+The results of SHOW STATUS EXTENDED LIKE 'alloc_ include the memory used by all per-segment vector indexes that are being used by vector search or vector range search.
The command SHOW STATUS EXTENDED LIKE 'alloc_ does not output any rows if the memory used by vector indexes is zero.
Output Format for Examples
Vectors can be output in JSON or binary format.
Use the following command to output vectors in JSON format.
SET vector_type_project_format = JSON;
Use the following command to set the output format back to binary.
SET vector_type_project_format = BINARY;
Example 1
Create a table with a VECTOR attribute and then create an IVF_ index on the vector column with index building parameter nlist set to 1024 and search parameter nprobe set to 20.
CREATE TABLE vect (k int, v VECTOR(2) NOT NULL);INSERT INTO vect VALUES(1, '[-10, 1]'),(2, '[10, 2]'),(3, '[20, 3]');ALTER TABLE vect ADD VECTOR INDEX (v) INDEX_OPTIONS'{"index_type":"IVF_PQFS", "nlist":1024, "nprobe":20}';
Note that the search parameter nprobe is used in this index creation command.INDEX_ during index creation.nprobe in this example) in index creation will be used as the default value for that search parameter for that index.
Optimize the table to ensure all results are indexed.
OPTIMIZE TABLE vect FLUSH;
Searching the nearest neighbor can be done with the commands below.
The @query_ variable is cast to a VECTOR to ensure that @query_ is a valid VECTOR and to improve performance.
SET vector_type_project_format = JSON; /* to make vector output readable */SET @query_vec = ('[9,0]'):> VECTOR(2);/* run the SET commands before this query */SELECT k, v, v <*> @query_vec AS scoreFROM vectORDER BY score DESC LIMIT 1;
+------+--------+------------------+
| k | v | score |
+------+--------+------------------+
| 3 | [20,3] | 180 |
+------+--------+------------------+You can increase k, as shown in the example below, to increase the number of rows output by the vector index scan.k will increase the search space and likely increase the recall, but will also increase the execution time of the query.
SET vector_type_project_format = JSON; /* to make vector output readable */SELECT k, v, v <*> '[9, 0]' AS scoreFROM vectORDER BY score SEARCH_OPTIONS '{"k" : 30 }' DESCLIMIT 3;
+------+---------+-------------------------------+
| k | v | score |
+------+---------+-------------------------------+
| 3 | [20,3] | 180 |
| 2 | [10,2] | 90 |
| 1 | [-10,1] | -90 |
+------+---------+-------------------------------+Example 2
Below is a small, self-contained example.
Create and use a new database:
CREATE DATABASE ann_vectors;USE ann_vectors;
Set the SQL Mode:
SET sql_mode = pipes_as_concat;
Create a table:
CREATE TABLE ann_test(id INT, v VECTOR(2) NOT NULL, SHARD KEY(id), KEY (id));
Use the following SQL script to generate data:
DELIMITER //DODECLARE s INT = 1*1024*1024;DECLARE c BIGINT;BEGININSERT ann_test VALUES(1,"[0,0]");LOOPINSERT INTO ann_testSELECT id+(SELECT MAX(id) FROM ann_test),"[" || s*rand() || "," || s*rand() || "]"FROM ann_test;SELECT COUNT(*) INTO c FROM ann_test;IF c >= s thenEXIT;END IF;END LOOP;END//DELIMITER ;
Add a vector index to the table:
ALTER TABLE ann_test ADD VECTOR INDEX(v)INDEX_OPTIONS '{"index_type":"IVF_PQFS", "nlist":1024,"metric_type":"EUCLIDEAN_DISTANCE"}';
Find a query vector as the vector for row 1000:
SET @qv = (SELECT v FROM ann_test WHERE id = 1000);
Find top five closest matches to the query vector:
SELECT id, v, v <-> @qv AS scoreFROM ann_testORDER BY scoreLIMIT 5;
Verify a Vector Index is Being Used
It is important to verify that your query is using a vector index.
-
The metric in the query (dot product vs.
euclidean distance) matches the metric used to create the index. -
The order in the
ORDER BYclause (DESCvs.ASC) in the search query matches the metric.
To get a detailed view of query plan for vector similarity queries, use EXPLAIN.EXPLAIN plan for the previous example is shown below.
EXPLAIN SELECT id, v, v <-> @qv AS scoreFROM ann_testORDER BY scoreLIMIT 5;
+----------------------------------------------------------------------------------------------+
| EXPLAIN |
+----------------------------------------------------------------------------------------------+
| Project [remote_0.id, remote_0.v, remote_0.score] |
| TopSort limit:5 [remote_0.score] |
| Gather partitions:all alias:remote_0 parallelism_level:segment |
| Project [ann_test.id, ann_test.v, EUCLIDEAN_DISTANCE(ann_test.v,@qv) AS score] |
| TopSort limit:5 [EUCLIDEAN_DISTANCE(ann_test.v,@qv)] |
| ColumnStoreFilter [INTERNAL_VECTOR_SEARCH(0, @qv, 5, '') index] |
| ColumnStoreScan ann_vectors.ann_test, SORT KEY __UNORDERED () table_type:sharded_columnstore |
+----------------------------------------------------------------------------------------------+The ColumnStoreFilter line of the EXPLAIN output above shows INTERNAL_ which indicates that the vector index is being used.INTERNAL_ is not in the ColumnStoreFilter line, the vector index is not being used.
Index Hints Example
The query below will specify the use of the index with key name v.
Use the vect table from Example 1 above for this query and the following one.
SELECT k, v <*> ('[9, 0]' :> VECTOR(2)) AS scoreFROM vectORDER BY score USE INDEX (v) DESCLIMIT 2;
The query below, which contains a USE INDEX clause without an index name, will disable the use of the vector (ANN) indexes.
SELECT k, v <*> ('[9, 0]' :> VECTOR(2)) AS scoreFROM vectORDER BY score USE INDEX () DESCLIMIT 2;
The query below specifies that the index v should be used and specifies a search option for the parameter k.USE_ clause and the SEARCH_ clause must appear immediately after the ORDER BY clause and USE_ must appear before SEARCH_.
SELECT k, v <*> ('[9, 0]' :> VECTOR(2)) AS scoreFROM vectORDER BY scoreUSE INDEX (v) SEARCH_OPTIONS '{"k":30}' DESCLIMIT 2;
As described above, EXPLAIN can be used to verify if the query does or does not use an index.
Note
Recall that ORDER BY should be in descending order (DESC) when you are using the DOT PRODUCT metric and in ascending order (ASC) when you are using the EUCLIDEAN DISTANCE metric.
When to use an ANN Index to Support Vector Search
In general, you should use ANN search for large sets of vectors when you do not have selective filters on other columns in the query.
On the other hand, if you have a smaller set of vectors, say less than a few million, and selective filters in your queries on other non-vector columns, you're often better off not using ANN indexes.
Related Topics
Last modified: September 25, 2025