This is an automated email from the ASF dual-hosted git repository. reshke pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/cloudberry.git
commit 2b72516adb6a6a2fe1ae0419e712e8a987f39f7c Author: Chris Hajas <[email protected]> AuthorDate: Mon Aug 7 15:57:35 2023 -0700 Fall back to planner for queries on relations with pgvector index When querying a relation with an `ivfflat` index from pgvector, Orca won't currently generate this index alternative. This will take a bit of work to support in Orca for a few reasons: generating index scans for this particular plan shape, creating the correct checks to ensure we generate a valid index plan, and proper costing for ivfflat indexes. For now, fall back to planner to ensure users can still generate plans with index scans. Note that Orca will not fall back if no index is present--Orca can generate those plans without any issues. No test is included since pgvector isn't part of this repo. Test case: ``` CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3)); INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'); CREATE INDEX ON items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100); explain SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5; NOTICE,"Feature not supported: Queries on relations with pgvector indexes (ivfflat) are not supported" QUERY PLAN ---------------------------------------------------------------------------------------------------------- Limit (cost=23.65..23.74 rows=5 width=48) -> Gather Motion 3:1 (slice1; segments: 3) (cost=23.65..23.91 rows=15 width=48) Merge Key: ((embedding <-> '[3,1,2]'::vector)) -> Limit (cost=23.65..23.71 rows=5 width=48) -> Index Scan using items_embedding_idx on items (cost=6.00..182.48 rows=15567 width=48) Order By: (embedding <-> '[3,1,2]'::vector) Optimizer: Postgres query optimizer (7 rows) ``` --- src/backend/access/index/amapi.c | 19 ++++++++++ src/backend/gpopt/gpdbwrappers.cpp | 11 ++++++ .../gpopt/translate/CTranslatorRelcacheToDXL.cpp | 42 +++++++++++++++++----- src/include/access/amapi.h | 1 + src/include/gpopt/gpdbwrappers.h | 2 ++ 5 files changed, 66 insertions(+), 9 deletions(-) diff --git a/src/backend/access/index/amapi.c b/src/backend/access/index/amapi.c index 028b8e9999..0612051e1c 100644 --- a/src/backend/access/index/amapi.c +++ b/src/backend/access/index/amapi.c @@ -152,3 +152,22 @@ amvalidate(PG_FUNCTION_ARGS) PG_RETURN_BOOL(result); } + +/* + * GetAmName + * Retrieve the name of a relation's access method + */ +char * +GetAmName(Oid amoid) +{ + Form_pg_am amform; + HeapTuple tuple; + + tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relam object %u", amoid); + + amform = (Form_pg_am) GETSTRUCT(tuple); + ReleaseSysCache(tuple); + return NameStr(amform->amname); +} diff --git a/src/backend/gpopt/gpdbwrappers.cpp b/src/backend/gpopt/gpdbwrappers.cpp index fa3c6727de..87533cdf03 100644 --- a/src/backend/gpopt/gpdbwrappers.cpp +++ b/src/backend/gpopt/gpdbwrappers.cpp @@ -34,6 +34,7 @@ #include "catalog/pg_collation.h" extern "C" { +#include "access/amapi.h" #include "access/external.h" #include "catalog/pg_inherits.h" #include "foreign/fdwapi.h" @@ -2776,4 +2777,14 @@ gpdb::IsTypeRange(Oid typid) return false; } +char * +gpdb::GetRelAmName(Oid reloid) +{ + GP_WRAP_START; + { + return GetAmName(reloid); + } + GP_WRAP_END; + return nullptr; +} // EOF diff --git a/src/backend/gpopt/translate/CTranslatorRelcacheToDXL.cpp b/src/backend/gpopt/translate/CTranslatorRelcacheToDXL.cpp index d6dce73868..a6eca18fbe 100644 --- a/src/backend/gpopt/translate/CTranslatorRelcacheToDXL.cpp +++ b/src/backend/gpopt/translate/CTranslatorRelcacheToDXL.cpp @@ -2751,15 +2751,39 @@ CTranslatorRelcacheToDXL::IsIndexSupported(Relation index_rel) HeapTupleData *tup = index_rel->rd_indextuple; // index expressions and index constraints not supported - return gpdb::HeapAttIsNull(tup, Anum_pg_index_indexprs) && - gpdb::HeapAttIsNull(tup, Anum_pg_index_indpred) && - index_rel->rd_index->indisvalid && - (BTREE_AM_OID == index_rel->rd_rel->relam || - HASH_AM_OID == index_rel->rd_rel->relam || - BITMAP_AM_OID == index_rel->rd_rel->relam || - GIST_AM_OID == index_rel->rd_rel->relam || - GIN_AM_OID == index_rel->rd_rel->relam || - BRIN_AM_OID == index_rel->rd_rel->relam); + BOOL index_supported = gpdb::HeapAttIsNull(tup, Anum_pg_index_indexprs) && + gpdb::HeapAttIsNull(tup, Anum_pg_index_indpred) && + index_rel->rd_index->indisvalid && + (BTREE_AM_OID == index_rel->rd_rel->relam || + HASH_AM_OID == index_rel->rd_rel->relam || + BITMAP_AM_OID == index_rel->rd_rel->relam || + GIST_AM_OID == index_rel->rd_rel->relam || + GIN_AM_OID == index_rel->rd_rel->relam || + BRIN_AM_OID == index_rel->rd_rel->relam); + if (index_supported) + { + return true; + } + + // Fall back if query is on a relation with a pgvector index (ivfflat) + // Orca currently does not generate index scan alternatives here + // Fall back to ensure users can get better performing index plans using planner + CAutoMemoryPool amp; + CMemoryPool *mp = amp.Pmp(); + CWStringDynamic *am_name_str = CDXLUtils::CreateDynamicStringFromCharArray( + mp, gpdb::GetRelAmName(index_rel->rd_rel->relam)); + + CWStringConst str_pgvector_am(GPOS_WSZ_LIT("ivfflat")); + if (am_name_str->Equals(&str_pgvector_am)) + { + GPOS_DELETE(am_name_str); + GPOS_RAISE( + gpdxl::ExmaMD, gpdxl::ExmiMDObjUnsupported, + GPOS_WSZ_LIT( + "Queries on relations with pgvector indexes (ivfflat) are not supported")); + } + GPOS_DELETE(am_name_str); + return false; } //--------------------------------------------------------------------------- diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index a30f4bb6a6..0f4a09d96e 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -289,6 +289,7 @@ typedef struct IndexAmRoutine extern bool IsIndexAccessMethod(Oid relam, Oid indexAccessMethod); extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler); extern IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid, bool noerror); +extern char *GetAmName(Oid amoid); /* Hook for plugins to get control in appendonly_delete() */ typedef void (*appendonly_delete_hook_type) (Relation rel, ItemPointer tid); diff --git a/src/include/gpopt/gpdbwrappers.h b/src/include/gpopt/gpdbwrappers.h index fbff5c4f27..f6ae7c4932 100644 --- a/src/include/gpopt/gpdbwrappers.h +++ b/src/include/gpopt/gpdbwrappers.h @@ -680,6 +680,8 @@ TargetEntry *FlatCopyTargetEntry(TargetEntry *src_tle); bool IsTypeRange(Oid typid); +char *GetRelAmName(Oid reloid); + } //namespace gpdb #define ForEach(cell, l) \ --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
