L'AI dove vivono i dati aziendali (parte 4): Ricerca vettoriale indicizzata con SQL Server 2025

Punto di partenza

Nel terzo articolo di questa serie abbiamo usato gli embeddings generati in precedenza per eseguire ricerche semantiche direttamente da T-SQL con la funzione VECTOR_DISTANCE.

Abbiamo trasformato una richiesta espressa in linguaggio naturale in un vettore, lo abbiamo confrontato con gli embeddings salvati nella tabella ai_demo.PostSearchDocuments e ordinato il risultato in base alla distanza semantica.

La ricerca con VECTOR_DISTANCE ci ha permesso di comprendere il funzionamento della ricerca vettoriale che funziona bene su insiemi di dati contenuti o già filtrati. Quando il numero di documenti cresce, però, diventa importante valutare strumenti più adatti alla ricerca vettoriale su volumi maggiori.

In questo quarto articolo creeremo un indice vettoriale sulla colonna Embedding e useremo la funzione VECTOR_SEARCH per eseguire ricerche semantiche approssimate. Vedremo anche alcune limitazioni attualmente presenti in SQL Server 2025 sugli indici vettoriali, aspetto importante da considerare prima di applicare queste funzionalità in produzione.

Con VECTOR_DISTANCE abbiamo eseguito una ricerca vettoriale esatta: per ogni riga candidata, SQL Server calcola la distanza tra il vettore della richiesta e il valore salvato nella colonna Embedding. Questo approccio è semplice da comprendere e utile per verificare la qualità degli embeddings e dei risultati restituiti.

Quando il numero di righe cresce, però, confrontare il vettore della richiesta con tutti gli embeddings candidati può diventare oneroso e degradare le performance della query. In questi scenari entra in gioco la ricerca vettoriale approssimata, indicata anche come approximate nearest neighbors. Invece di calcolare in modo esaustivo la distanza verso tutti i vettori candidati, l’engine di SQL Server può usare un indice vettoriale per individuare rapidamente i vettori più vicini.

La funzione VECTOR_SEARCH permette di eseguire questo tipo di ricerca. Il risultato restituito include le colonne della tabella indicata nella funzione e una colonna aggiuntiva distance, che rappresenta la distanza tra il vettore di ricerca e il vettore salvato nella colonna indicata.

Come descritto nella documentazione ufficiale sulla ricerca vettoriale nell’engine SQL, un indice vettoriale ha un significato diverso rispetto a un indice relazionale tradizionale. Serve a rendere più efficiente la ricerca dei vettori più vicini, accettando un compromesso controllato tra accuratezza e prestazioni. Il risultato non va interpretato come una sostituzione del modello relazionale, ma come un nuovo strumento da combinare con filtri, metadati e criteri già presenti nel database.

Creazione dell’indice vettoriale

Per usare VECTOR_SEARCH in uno scenario di ricerca approssimata è necessario creare un indice vettoriale sulla colonna che contiene gli embeddings. Nel nostro caso la colonna è Embedding nella tabella ai_demo.PostSearchDocuments.

L’istruzione CREATE VECTOR INDEX permette di creare un indice approssimato su una colonna di tipo VECTOR, migliorando le performance delle ricerche nearest neighbors.

Nel seguente esempio creiamo un indice vettoriale usando la metrica cosine, la stessa usata negli esempi precedenti con VECTOR_DISTANCE. Il tipo di indice è DiskANN, attualmente l’algoritmo supportato per questo tipo di ricerca.

CREATE VECTOR INDEX IDX_VECTOR_PostSearchDocuments_Embedding ON [ai_demo].[PostSearchDocuments]
(
  [Embedding]
)
WITH
(
  METRIC = 'cosine'
  ,TYPE = 'diskann'
);
GO

La scelta della metrica è importante: l’indice vettoriale deve essere coerente con la metrica che verrà usata nelle query di ricerca. In questo caso continueremo a usare la metrica cosine, adatta a confrontare embeddings testuali in scenari di ricerca semantica.

Prima di creare un indice vettoriale è importante ricordare che la funzionalità è ancora in preview in SQL Server 2025. Inoltre, la tabella deve contenere almeno 100 righe con vettori non NULL nella colonna indicizzata. In caso contrario, la creazione dell’indice non potrà essere completata.

Limitazioni attuali in SQL Server 2025

Prima di vedere in azione l’indice appena creato è importante evidenziare alcune limitazioni. Le funzionalità di indicizzazione vettoriale in SQL Server 2025 sono attualmente in preview e il comportamento può variare rispetto ad Azure SQL Database e SQL database in Microsoft Fabric, dove sono disponibili versioni più recenti degli indici vettoriali.

In SQL Server 2025, gli indici vettoriali possono usare, al momento, la prima implementazione di questa tecnologia. Il supporto completo alle operazioni DML e il filtering iterativo non sono ancora disponibili.

In SQL Server 2025, la creazione di un indice vettoriale pone la tabella in read-only. Inoltre, i predicati relazionali possono essere applicati dopo la ricerca vettoriale e non durante il processo di ricerca stesso, aspetto da considerare quando si combinano VECTOR_SEARCH e filtri T-SQL. È importante tenere presenti questi aspetti prima di applicare indici vettoriali in produzione.

Verifica della versione dell’indice vettoriale

Dopo la creazione dell’indice è utile verificarne la versione interrogando le viste di sistema. Questa informazione permette di capire quale implementazione dell’indice vettoriale è stata usata nell’ambiente in cui stiamo lavorando.

La vista sys.vector_indexes espone le informazioni relative agli indici vettoriali. Nel seguente esempio leggiamo il nome dell’indice, la tabella associata e la versione dell’indice dai parametri di build.

SELECT
  I.[name] AS IndexName
  ,T.[name] AS TableName
  ,JSON_VALUE(VI.build_parameters, '$.Version') AS VectorIndexVersion
FROM
  sys.vector_indexes AS VI
JOIN
  sys.indexes AS I ON I.[object_id] = VI.[object_id] AND I.index_id = VI.index_id
JOIN
  sys.tables AS T ON T.[object_id] = VI.[object_id]
WHERE
  I.[name] = N'IDX_VECTOR_PostSearchDocuments_Embedding';
GO

In SQL Server 2025, il valore restituito nella colonna VectorIndexVersion è NULL e sta a indicare la prima implementazione di questa tecnologia.

Dopo aver creato l’indice vettoriale possiamo usare VECTOR_SEARCH per eseguire una nuova ricerca semantica. Come negli esempi precedenti, partiamo da una richiesta espressa in linguaggio naturale e la trasformiamo in un embedding usando la funzione AI_GENERATE_EMBEDDINGS.

In questo esempio cerchiamo contenuti semanticamente vicini alla frase “SQL Server error log file is full”.

-- Approximate semantic search with VECTOR_SEARCH
DECLARE
  @SearchText NVARCHAR(MAX) =
  N'SQL Server error log file is full';
DECLARE
  @qv VECTOR(1536) = AI_GENERATE_EMBEDDINGS
                     (
                       @SearchText 
                       USE MODEL [AzureOpenAI_text_embedding_ada_002]
                     );

SELECT
  S.distance
  ,T.QuestionId
  ,T.AcceptedAnswerId
  ,T.QuestionScore
  ,T.AcceptedAnswerScore
  ,T.ViewCount
  ,T.Tags
  ,T.Title
FROM
  VECTOR_SEARCH
  (
    TABLE = [ai_demo].[PostSearchDocuments] AS T
    ,COLUMN = Embedding
    ,SIMILAR_TO = @qv
    ,METRIC = 'cosine'
    ,TOP_N = 10
  ) AS S
ORDER BY
  S.distance;
GO

La funzione VECTOR_SEARCH riceve in input la tabella su cui eseguire la ricerca, la colonna vettoriale da interrogare, il vettore da usare come riferimento e la metrica di distanza. Nel nostro caso la ricerca viene eseguita sulla colonna Embedding della tabella ai_demo.PostSearchDocuments, utilizzando la metrica cosine.

Il parametro TOP_N = 10 indica il numero massimo di vettori simili da restituire. Questa sintassi dipende dalla versione degli indici vettoriali in SQL Server 2025. Con versioni più recenti, come quelle disponibili in Azure SQL Database e SQL database in Microsoft Fabric, la sintassi è SELECT TOP (N) WITH APPROXIMATE.

La colonna distance, restituita da VECTOR_SEARCH, rappresenta la distanza tra il vettore della richiesta e i vettori individuati nella colonna Embedding. Ordinando i risultati per S.distance crescente, otteniamo per primi i testi semanticamente più vicini alla richiesta.

Uno sguardo al piano di esecuzione

Osservando il piano di esecuzione si vede il cambio di approccio rispetto alla ricerca con VECTOR_DISTANCE. In questo caso SQL Server non calcola la distanza su tutte le righe candidate, ma utilizza l’indice vettoriale creato sulla colonna Embedding.

Nel piano di esecuzione è presente il nuovo operatore Vector Index Seek, associato all’indice IDX_VECTOR_PostSearchDocuments_Embedding di tipo DiskANN. Questo operatore restituisce gli identificativi dei vettori più vicini e la relativa distanza.

I risultati restituiti da VECTOR_SEARCH vengono poi uniti alla tabella ai_demo.PostSearchDocuments tramite l’operatore Nested Loops. Per ogni identificativo restituito dalla ricerca vettoriale, SQL Server esegue un Clustered Index Seek sulla chiave primaria della tabella per recuperare le colonne richieste dalla SELECT.

VECTOR_SEARCH e filtri relazionali

Anche con VECTOR_SEARCH possiamo combinare la ricerca semantica con predicati T-SQL. Occorre però considerare il comportamento descritto in precedenza: con la prima implementazione degli indici vettoriali in SQL Server 2025, i predicati relazionali possono essere applicati dopo la ricerca vettoriale.

Nel seguente esempio cerchiamo contenuti semanticamente vicini alla frase “How to debug a SQL Server trigger?” e applichiamo un filtro sul punteggio della domanda.

-- Approximate semantic search with an additional relational filter
-- TOP_N is intentionally larger because the relational filter is applied after the vector search result set
DECLARE
  @SearchText NVARCHAR(MAX) =
  N'How to debug a SQL Server trigger?';
DECLARE
  @qv VECTOR(1536) = AI_GENERATE_EMBEDDINGS
                     (
                       @SearchText 
                       USE MODEL [AzureOpenAI_text_embedding_ada_002]
                     );

SELECT
  TOP (10)
  S.distance
  ,T.QuestionId
  ,T.Title
  ,T.Tags
  ,T.QuestionScore
  ,T.AcceptedAnswerScore
FROM
  VECTOR_SEARCH
  (
    TABLE = [ai_demo].[PostSearchDocuments] AS T
    ,COLUMN = Embedding
    ,SIMILAR_TO = @qv
    ,METRIC = 'cosine'
    ,TOP_N = 50
  ) AS S
WHERE
  T.QuestionScore >= 5
ORDER BY
  S.distance;
GO

Il parametro TOP_N = 50 è intenzionalmente più alto del numero finale di righe richieste. La ricerca vettoriale restituisce prima un insieme di vettori semanticamente vicini, poi il predicato QuestionScore >= 5 restringe il risultato ai contenuti che rispettano anche questo predicato.

Quando si lavora con la prima versione degli indici vettoriali, se TOP_N è troppo basso, i predicati relazionali potrebbero eliminare parte dei risultati restituiti dalla ricerca vettoriale, fino a produrre meno righe di quelle desiderate. Con le versioni più recenti degli indici vettoriali, il comportamento è diverso grazie al filtering iterativo, dove i predicati vengono considerati durante il processo di ricerca.

VECTOR_DISTANCE è utile quando si vuole comprendere il funzionamento della ricerca vettoriale, verificare la qualità degli embeddings o lavorare su insiemi di dati contenuti o già filtrati. Il risultato è una ricerca esatta, semplice da leggere e da controllare.

VECTOR_SEARCH diventa interessante quando il numero di vettori cresce e si vuole usare una ricerca più adatta a volumi maggiori. È necessario prestare attenzione alla versione dell’indice vettoriale, alla sintassi supportata dall’ambiente e al comportamento dei predicati relazionali.

La scelta tra i due approcci non è quindi assoluta. Dipende dal volume dei dati, dal livello di accuratezza richiesto, dalle funzionalità disponibili nell’ambiente SQL utilizzato e dal modo in cui la ricerca semantica deve essere combinata con il modello relazionale.

Conclusioni

In questo articolo abbiamo creato un indice vettoriale sulla colonna Embedding della tabella ai_demo.PostSearchDocuments e usato VECTOR_SEARCH per eseguire ricerche semantiche approssimate direttamente da T-SQL.

Abbiamo visto che gli indici vettoriali permettono a SQL Server di usare un approccio diverso rispetto al calcolo esplicito della distanza su tutte le righe candidate. Il piano di esecuzione mostra infatti l’utilizzo del nuovo operatore Vector Index Seek, che sfrutta l’indice DiskANN per individuare i vettori più vicini.

Nel prossimo articolo faremo un approfondimento su Azure SQL, dove sono disponibili versioni più recenti degli indici vettoriali e dove alcune delle limitazioni viste in SQL Server 2025 non sono più presenti.