Skip to content

PS-11203 Vector Index Syntax - #5987

Open
percona-mhansson wants to merge 5 commits into
percona:vector-mvpfrom
percona-mhansson:vector-mvp-syntax
Open

PS-11203 Vector Index Syntax#5987
percona-mhansson wants to merge 5 commits into
percona:vector-mvpfrom
percona-mhansson:vector-mvp-syntax

Conversation

@percona-mhansson

@percona-mhansson percona-mhansson commented May 29, 2026

Copy link
Copy Markdown
Contributor

Stacked on #6000

@percona-mhansson percona-mhansson changed the title Vector mvp syntax PS-11203 Vector Index Syntax May 29, 2026
@percona-mhansson
percona-mhansson force-pushed the vector-mvp-syntax branch 3 times, most recently from c055ddc to bac48eb Compare June 9, 2026 13:47
@percona-mhansson
percona-mhansson force-pushed the vector-mvp-syntax branch 2 times, most recently from a985587 to 96481cb Compare June 10, 2026 14:24
@percona-mhansson
percona-mhansson force-pushed the vector-mvp-syntax branch 5 times, most recently from 3c65f43 to 67722d7 Compare June 26, 2026 13:52
@percona-mhansson
percona-mhansson force-pushed the vector-mvp-syntax branch 2 times, most recently from 09426a6 to b22f12a Compare July 21, 2026 06:29
eng "Vector index can only be created in tables with a BIGINT UNSIGNED primary key."

ER_ONLY_SINGLE_VECTOR_INDEX_ALLOWED
eng "A table can have at most one vector index."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this the case? I've seen examples where having two indexed vector columns make a lot of sense. Is this only for the MVP?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread sql/handler.h
inline constexpr const decltype(handlerton::flags)
HTON_SECONDARY_SUPPORTS_TEMPORARY_TABLE(1 << 25);


Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert these changes to the end of the file as they are not related to this commit

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. These were actually part of the underlying PR, so I'll update that one, too.

);
SHOW CREATE TABLE t1;
SHOW INDEXES FROM t1;

@catalinbp catalinbp Jul 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't have any test cases where you try creating a VECTOR index on a table without BIGINT UNSIGNED, also one where you create the table with such primary key but then you alter the table by droping it or perhaps change data type(though I think the second part of this idea should not be possible)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread storage/innobase/handler/vec0vec.cc Outdated
}
hnsw_param.M = std::atoi(p.value.str);
} else if (my_strcasecmp(system_charset_info, p.key.str, "metric") == 0) {
if (my_strcasecmp(system_charset_info, p.value.str, "euclidean") == 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how will this tie into the distance functions? does it need to support all the metrics?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also wonder what visibility do we have from the optimizer if an index is defined on one metric and we query it using distance function using another metric. Shouldn't this be more "static" since there are only a few available options?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. I changed the code to make it more obvious how to add new metrics. If you have a list of metrics already, feel free to drop them!

Not sure what you mean by static? You mean coded into the Bison parser?

Comment thread sql/sql_table.cc Outdated
Comment thread sql/sql_yacc.yy Outdated
}
;

index_construction_parameter:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it's a good idea to expect IDENT_QUOTED instead of IDENT. As far as I know the former accepts non-ASCII bytes/multi-byte. This should be a simple config and I don't expect anything "exotic" here, it's easier to start with something restricted, and relax requirements later

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some ugly lexer hack around IDENT, I never managed to get it to work

mysql> CREATE TABLE t1 (   id BIGINT UNSIGNED PRIMARY KEY,   v1 VECTOR( 1234 ),   VECTOR KEY( v1 ) TYPE hnsw WITH ( m=a ) );
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'm=a ) )' at line 1

The rest of the string is eaten up by the IDENT above

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing to ident for now. That seems to be what people do

Comment thread storage/innobase/dict/dict0crea.cc Outdated
Comment thread storage/innobase/handler/vec0vec.cc Outdated
Comment thread storage/innobase/include/vec0vec.h Outdated
Comment thread .gitignore Outdated
Comment thread sql/sql_yacc.yy
| XML_SYM
| YEAR_SYM
| ZONE_SYM
| VECTOR_SYM

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this necessary? this makes VECTOR a reserved keyword so this will break existing schema using this name

@percona-mhansson percona-mhansson Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will be almost impossible to support the VECTOR INDEX syntax we have without it. Currently it's perfectly legal to define a column named vector:

CREATE TABLE t ( ..., vector  char(1) )

Heck, you can even do CREATE TABLE t ( ..., vector VECTOR(1) )!

We want to support the syntax to create an in-line vector definition

CREATE TABLE t ( ..., vector index ix (col) )

You can probably see where this is going.
We have these options afaiu:

  • Re-shuffle the rules so we never reduce a until we have the full set of items. Only then can we know whether it's a column definition or an index definition
  • Not do the VECTOR INDEX syntax at all, only INDEX and let type TYPE/USING clause decide. Fwiw, this seems to be what Oracle are considering.
  • Do as above and make VECTOR a properly reserved word
  • We could also in theory create another category of reserved words which can be used as anything but column names :P

Comment thread sql/sql_table.cc
key_create_info.comment = key_info->comment;

if (key_info->vector_index_type.str != nullptr)
key_create_info.vector_index_type = key_info->vector_index_type;

@catalinbp catalinbp Jul 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this where the other parameters of the index config gets lots and triggers this bug:

CREATE TABLE t1 (
  id BIGINT UNSIGNED PRIMARY KEY,
  v1 VECTOR( 8 ),
  VECTOR KEY( v1 ) TYPE hnsw WITH ( M = 6, metric = euclidean )
);
SHOW CREATE TABLE t1;

# Unrelated ALTER
ALTER TABLE t1 ADD COLUMN c INT;
# see how the parameters gets lost
SHOW CREATE TABLE t1;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ouch. This was a particularly gnarly issue. It made me re-implement where the whole serialization and de-serialization happens. But it's probably cleaner this way.

Comment thread sql/sql_table.cc Outdated
assert((key_info->flags & flags_before_switch) == flags_before_switch);
if (key->generated) key_info->flags |= HA_GENERATED_KEY;

// Serialize vector index construction params (WITH clause).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CREATE TABLE t2 ( a INT, KEY k ( a ) TYPE hnsw WITH ( M = 6 ) ); should not be accepted

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't now 😄

mysql> CREATE TABLE t2 ( a INT, KEY k ( a ) TYPE hnsw WITH ( M = 6 ) );
ERROR 7034 (HY000): A VECTOR index may only contain a vector type column.

@percona-mhansson
percona-mhansson force-pushed the vector-mvp-syntax branch 5 times, most recently from 96b9e15 to f857287 Compare August 13, 2026 08:20
Vector indexes have the type (algorithm) SE_SPECIFIC, and we add a column option
in the data dictionary saying `vector_index=1;` which gets picked up by
dedicated code in the data dictionary and the handler part of InnoDB.

In the SQL layer, the vector index is very much a thing; there is an
`HA_KEY_ALG_VECTOR`, an `HA_VECTOR` and a `KEYTYPE_VECTOR`.

Extra SQL is added to display the type of a vector index as VECTOR rather than
SE_SPECIFIC.
Adding the syntax `TYPE <ident> WITH ( <ident> = <ident>...) ` to index creation
syntax. E.g.:

`CREATE INDEX <name> ( <table> ) TYPE hnsw WITH ( M = 6 )`

The syntax in the `WITH` list, christened Index Construction Parameters in this
commit, must be verified by the storage engine. There were no hooks for this in
InnoDB so one has been added in check_engine().  We have to do it fairly early
so that we can prevent table creation in the DD in case of errors.  Hence, the
index type and parameter list are validated inside the storage engine using a
new interface validate_engine_attributes().

The index construction parameters are serialized as a string of key-value pairs
inside the index's `option` field. The serialization and de-serialization happen
entirely inside the Data Dictionary.

To do: We will probably still need a hook to handle the case of an
already-existing table with invalid attributes; there are no hooks for this.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants