This guide details the Oracle Database 26ai integration, SQLSpec usage, vector search, HNSW index management, and local database lifecycle patterns.
- Database: Oracle Database 26ai (Vector Search, RAG, Graph RAG)
- Data Access: SQLSpec (using
python-oracledbandmypycoptimizations) - Supported Types: The baseline schema leverages modern Oracle types:
BOOLEANJSONVECTOR(3072, FLOAT32)(used for product vectors and embedding cache)
Domain services subclass SQLSpecAsyncService (from app.lib.service) or OracleAsyncService.
All static SQL queries must live in src/app/db/sql/*.sql as named queries. Domain services call db_manager.get_sql("query-name"). Inline static SQL strings in Python code are rejected.
Always pass schema_type= when executing reads where a typed msgspec Struct schema exists:
rows = await self.driver.select(
db_manager.get_sql("list-products"),
schema_type=Product,
)Use SQLSpec builders (sql.update, sql.insert_into) only for dynamic writes to avoid complex string assembly:
result = await self.driver.execute(
sql.update("product").set(embedding=embedding).where_eq("id", product_id)
)SQLSpec handles binding Python list[float] directly to Oracle vector columns. Do not wrap vectors in array.array("f", ...) in Python.
Always use named bind parameters in the format :name in SQL files. Never interpolate user input directly into SQL strings.
Oracle 26ai supports database annotations.
- Keep
COMMENT ONstatements for backwards compatibility. - Use 26ai
ANNOTATIONS(...)on tables, columns, and indexes. - Place annotations directly in the baseline DDL (e.g.,
0001_cymball_coffee_products.sql). Do not create separateALTER ... ANNOTATIONS(...)migration steps. - Annotations are validated using the
USER_ANNOTATIONS_USAGEdictionary view.
The application standardized on:
- Model:
gemini-embedding-2 - Dimensions:
3072 - Storage:
VECTOR(3072, FLOAT32) - Similarity Formula:
1 - VECTOR_DISTANCE(embedding, :query_vector, COSINE)
HNSW indexes use Oracle's ORGANIZATION INMEMORY NEIGHBOR GRAPH:
CREATE VECTOR INDEX product_embedding_idx ON product (embedding)
ORGANIZATION INMEMORY NEIGHBOR GRAPH
DISTANCE COSINE
WITH TARGET ACCURACY 95
PARAMETERS (TYPE HNSW, NEIGHBORS 40, EFCONSTRUCTION 500);Oracle requires a non-zero vector_memory_size before creating INMEMORY neighbor graph indexes, otherwise migrations fail with ORA-51962.
- Local Development / Oracle Free: Constrained SGA/PGA limits require a small size:
ALTER SYSTEM SET vector_memory_size = 512M SCOPE = SPFILE;
- Larger Environments: Use a 4G target:
ALTER SYSTEM SET vector_memory_size = 4G SCOPE = SPFILE;
- Verification:
SELECT name, bytes FROM v$sgainfo WHERE name = 'Vector Memory Area';
- HNSW Sizing Formula (Rough Estimate):
1.3 * rows * dimensions * element_sizeElement sizes:FLOAT64: 8 bytesFLOAT32: 4 bytesINT8: 1 byteBINARY: 1/8 byte (1 bit) UseDBMS_VECTOR.INDEX_VECTOR_MEMORY_ADVISORfor exact sizing.
The /explore page allows executing a query and retrieving its execution plan:
EXPLAIN PLAN FOR SELECT ...;
SELECT plan_table_output FROM TABLE(DBMS_XPLAN.DISPLAY());Look for VECTOR in the output to confirm that the HNSW index is being hit. If it falls back to full table scan, verify index creation, vector_memory_size, and stats updates.
SQLSpec configuration wires extension tables for ADK and Litestar:
ORACLE_ADK_IN_MEMORY(default true): enables INMEMORY foradk_session,adk_event, and optional memory tables.ORACLE_LITESTAR_SESSION_IN_MEMORY(default true): enables INMEMORY forapp_session.
The contributor path runs a managed Oracle container. Use these commands to manage it:
# Start Oracle Free container
make start-infra
# Upgrade database schema (runs SQLSpec migrations)
uv run python manage.py database upgrade --no-prompt
# Load demo fixtures
uv run coffee load-fixturesFixture loading must happen in order:
stores(coordinates/place_ids)product(names, descriptions, stock booleans)- dependent semantic rows (embeddings, metrics)
To regenerate product embeddings:
- Load new product rows.
- Run
uv run coffee bulk-embedto generate vectors via Vertex AI. - Run
uv run coffee export-fixturesto save the updated product embeddings to the committed compressed files (product.json.gz). - Re-verify by running
uv run coffee load-fixturesto load the new embeddings.
ORA-51962during migration:vector_memory_sizeis zero or too small. Run the SPFILE alteration and restart the container.- Slow search / Index not used: Verify via the EXPLAIN PLAN tool on
/explore. Check that stats are gathered:DBMS_STATS.GATHER_TABLE_STATS. - Dimension mismatch: Confirm no older
768dimension vectors are present in migrations, fixtures, or code.