本文說明了自 18.6.1.1 版本起,Microsoft ODBC 驅動程式實作的 向量 SQL 資料型別。 本文件概述了 Microsoft 驅動程式對 向量的行為,並提供使用指引、API 專用說明及程式碼摘要。 關於向量資料型態的概述,請參見 向量資料型態。
概觀
Microsoft ODBC 驅動程式原生支援 向量 資料型態。 應用程式能有效儲存、檢索及處理固定維度的數值嵌入,這些嵌入常用於機器學習與人工智慧工作負載。 驅動程式透過標準 ODBC API 與 C 資料型態提供向量支援。 應用程式可以與 SQL Server 向量欄位互通,而無需更改現有的 ODBC 工作流程。
適用於:Microsoft ODBC 驅動程式 SQL Server 18.6.1.1 及更新版本。
對於 Microsoft 驅動程式(18.6.1.1),向量支援預設是被禁用的,必須明確啟用。
原生 C 表示法
啟用向量支援時,向量 欄位會使用名為 SQL_SS_VECTOR_STRUCT 的 C 型別結構來交換。
typedef struct tagSQL_SS_VECTOR_STRUCT {
SQLSMALLINT dimension; /* Number of elements */
SQLSMALLINT type; /* Element type indicator (0 = float32) */
union {
float *f32; /* Pointer to float32 data */
} data;
} SQL_SS_VECTOR_STRUCT;
-
dimension: 描述向量中元素的數量 -
type: 識別基底元素類型(目前float32) -
data.f32: 指向包含向量值的應用緩衝區
啟用向量支援
Microsoft 驅動程式會提供驅動程式專屬的 C 綁定
SQL_C_SS_VECTOR並支援在設定連線或驅動程式選項SQL_C_BINARY時,若使用vectorTypeSupport值,則可進行向量輸出支援v1。 在實踐中:當你啟用
vectorTypeSupport=v1時,檢索 API(例如SQLGetData和SQLBindCol)可以返回 向量 欄位,表示為SQL_C_SS_VECTORSQL_C_BINARY或 。SQL_C_SS_VECTOR以緊湊且具類型的形式回傳向量。SQL_C_BINARY回傳一個 變異型 有效載荷。對於輸入或參數綁定,Microsoft 驅動程式(18.6.1.1 版本,包含
vectorTypeSupport=v1)同時支援SQL_C_SS_VECTOR和SQL_C_BINARY。SQL_C_SS_VECTOR提供型別化且緊湊的輸入綁定。SQL_C_BINARY等同且便攜。 當你想讓驅動程式把有效載荷視為原生SQL_C_SS_VECTOR類型時,請使用。當
vectorTypeSupport=off時,向量欄位會以 varchar(max) 形式出現,包含 JSON 陣列。
應用程式在使用向量特定類型前,必須將 ODBC 版本設定為 ODBC 3.8:
SQLSetEnvAttr(
hEnv,
SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)SQL_OV_ODBC3_80,
0);
支援的綁定格式
原生載體結合
C 型: SQL_C_SS_VECTOR
此格式建議用於效能高的應用。
二元綁定
C 型: SQL_C_BINARY
向量的回傳將使用與SQL_C_SS_VECTOR相同的佈局。 應用程式可以使用此格式來應對低階互通情況。 資料指標緩衝區可以是連續的,也可以是非連續的,且帶有結構記憶體位址。
ODBC API 指引
本節說明 ODBC API 如何與 SQL Server 向量資料互動,包括緩衝區配置需求、 NULL 處理方式及支援的資料表示方式。 所有行為在 vectorTypeSupport=v1 啟用且環境設定為 ODBC 3.8 時適用。
SQLBindCol
用 SQLBindCol 來將結果集中的 向量 欄位綁定到應用程式緩衝區。
- 典型通話:
SQLRETURN SQLBindCol(
SQLHSTMT StatementHandle,
SQLUSMALLINT ColumnNumber,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLLEN BufferLength,
SQLLEN * StrLen_or_IndPtr);
TargetType:使用SQL_C_SS_VECTOR或SQL_C_BINARY。TargetValuePtr:指向一個包含SQL_SS_VECTOR_STRUCT陣列的的指標,當TargetType是SQL_C_SS_VECTOR時;否則,指向一個大小為StrLen_or_IndPtr值的緩衝區的指標。BufferLength:sizeof(SQL_SS_VECTOR_STRUCT)+ 欄位緩衝區所分配的位元組數(維度 * 4)。StrLen_or_IndPtr: 指標接收回傳向量的位元組長度 (SQL_DESC_OCTET_LENGTH)。 其值為sizeof(SQL_SS_VECTOR_STRUCT)+ 浮點 陣列大小(維度 * 4)。
緩衝區佈局的期望
非連續緩衝區(建議)
- 應用程式每列分配一個
SQL_SS_VECTOR_STRUCT。 - 應用程式會為
data.f32分配記憶體。 - 驅動程式會填充向量元資料,並將元素值寫入提供的 浮點 緩衝區。
SQLLEN numberOfRow = 1000; // set to SQL_ATTR_ROW_ARRAY_SIZE
SQLULEN columnSize = x; // use SQLDescribeCol or SQLColAttributeW or sizeof(SQL_SS_VECTOR_STRUCT) + (dimension * 4)
SQL_SS_VECTOR_STRUCT vecBuffer[numberOfRow]
std::vector<SQLLEN> indicator(numberOfRow, 0);
for (int i = 0; i < numberOfRow; i++)
{
vecBuffer[i].dimension = static_cast<SQLUSMALLINT>((columnSizes[col - 1] - sizeof(SQL_SS_VECTOR_STRUCT)) / 4);
vecBuffer[i].type = SQL_VECTOR_TYPE_FLOAT32;
vecBuffer[i].data.f32 = (float*)malloc(vecBuffer[i].dimension * sizeof(float));
if (!vecBuffer[i].data.f32) {
std::cerr << "Memory allocation failed for vector data." << std::endl;
return SQL_ERROR;
}
}
SQLBindCol(hStmt, col, SQL_C_SS_VECTOR, vecBuffer, columnSize, indicators.data());
連續緩衝區
- 應用程式分配單一緩衝區,ODBC 則相應填充。
- float 陣列必須在結構體之後立即開始。
- 驅動程式設定
data.f32指向這個相連區域。
SQLLEN numberOfRow = 1000; // set to SQL_ATTR_ROW_ARRAY_SIZE
SQLULEN columnSize = x; // use SQLDescribeCol or SQLColAttributeW or sizeof(SQL_SS_VECTOR_STRUCT) + (dimension * 4)
std::vector<BYTE> vecBuffer;
std::vector<SQLLEN> indicator(numberOfRow, 0);
vecBuffer.resize(numberOfRow * columnSize);
SQLBindCol(hStmt, col, SQL_C_BINARY, vecBuffer.data(), columnSize, indicators.data());
SQLBindCol 的 NULL 處理
當欄位值為 NULL時,驅動程式會設定 *StrLen_or_IndPtr 為 , SQL_NULL_DATA 且不會填入緩衝區。 在存取向量內容物前,務必先檢查指示器。
備註
向向量欄位的讀取與列擷取行為在SQLFetch及SQLFetchScroll中有詳細說明(參見 API 參考文獻中的擷取語法與陣列擷取範例)。
SQLGetData
用於 SQLGetData 從未綁定欄位取得向量資料。
- 典型通話:
SQLRETURN SQLGetData(
SQLHSTMT StatementHandle,
SQLUSMALLINT Col_or_Param_Num,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLLEN BufferLength,
SQLLEN * StrLen_or_IndPtr);
TargetType:使用SQL_C_SS_VECTOR或SQL_C_BINARY。TargetValuePtr:指向一個包含SQL_SS_VECTOR_STRUCT陣列的的指標,當TargetType是SQL_C_SS_VECTOR時;否則,指向一個大小為StrLen_or_IndPtr值的緩衝區的指標。BufferLength:sizeof(SQL_SS_VECTOR_STRUCT)+ 欄位緩衝區所分配的位元組數(維度 * 4)。StrLen_or_IndPtr: 指標接收回傳向量的位元組長度 (SQL_DESC_OCTET_LENGTH)。 其值為sizeof(SQL_SS_VECTOR_STRUCT)+ 浮點陣列大小(維度 * 4)。
不支援分塊檢索。 你必須一次通話中取回整個向量。
範例(原生 向量):
SQLLEN dataLen = 0;
SQL_SS_VECTOR_STRUCT vec = {};
vec.data.f32 = (float*)malloc(x * sizeof(float)); // x is the dimension
if (!vec.data.f32) {
std::cerr << "Memory allocation failed for vector data." << std::endl;
return SQL_ERROR;
}
SQLGetData(hStmt, col, SQL_C_SS_VECTOR, &vec, sizeof(vec) + sizeof(float) * vec.dimension, &dataLen);
SQLGetData 的 NULL 處理
當欄位值為 NULL時,驅動程式會設定 *StrLen_or_IndPtr 為 , SQL_NULL_DATA 且不會填入緩衝區。 在存取向量內容物前,務必先檢查指示器。
備註
向向量欄位的讀取與列擷取行為在SQLFetch及SQLFetchScroll中有詳細說明(參見 API 參考文獻中的擷取語法與陣列擷取範例)。
SQLFetch
用 SQLFetch 來擷取下一列,並正確地將任何綁定在 SqlVector 的欄位實現。
- 典型通話:
SQLRETURN SQLFetch(
SQLHSTMT StatementHandle);
在標準迴圈中呼叫 SQLFetch,SqlVector 欄位已透過 SQLBindCol 綁定。 或者,用來 SQLGetData 將資料取回應用程式緩衝區。
範例(原生 向量):
while ((ret = SQLFetch(hStmt)) == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
// if SQLBindCol was used directly jump to read buffer
// else use SQLGetData and than read buffer.
std::cout << " data: [";
if (dataLen != SQL_NULL_DATA)
{
for (SQLUSMALLINT d = 0; d < vec.dimension; ++d) {
std::cout << vec.data.f32[d];
if (d + 1 < vec.dimension) std::cout << ", ";
}
}
std::cout << "]" << std::endl;
}
SQLFetchScroll
請使用 SQLFetchScroll 以根據指定方向(next、prior、absolute、relative、bookmark)擷取行集。 驅動程式會正確地將向量資料複製到應用程式緩衝區。
- 典型通話:
SQLRETURN SQLFetchScroll(
SQLHSTMT StatementHandle,
SQLSMALLINT FetchOrientation,
SQLLEN FetchOffset);
範例(原生 向量):
// Fetch rows in batches
while ((ret = SQLFetchScroll(hStmt, SQL_FETCH_NEXT, 0)) != SQL_NO_DATA) {
for (SQLULEN i = 0; i < numRowsFetched; i++) {
// In case of Contiguous Buffer
SQL_SS_VECTOR_STRUCT* vecptr = reinterpret_cast<SQL_SS_VECTOR_STRUCT*>(
vecBuffer.data() + (i * columnSizes[col - 1]));
float* floats = reinterpret_cast<float*>(
reinterpret_cast<char*>(vecptr) + sizeof(SQL_SS_VECTOR_STRUCT)
);
// in Case of non-contiguous Buffer
SQL_SS_VECTOR_STRUCT* vecptr = &vecBuffer[i];
float* floats = vecptr->data.f32;
if (indicators[i] != SQL_NULL_DATA)
{
for (SQLUSMALLINT d = 0; d < vecptr->dimension; ++d) {
std::cout << floats[d];
if (d + 1 < vecptr->dimension) std::cout << ", ";
}
}
std::cout << "]" << std::endl;
}
}
SQLBindParameter
用 SQLBindParameter 來傳送向量值到 SQL Server。
- 典型通話:
SQLRETURN SQLBindParameter(
SQLHSTMT StatementHandle,
SQLUSMALLINT ParameterNumber,
SQLSMALLINT InputOutputType,
SQLSMALLINT ValueType,
SQLSMALLINT ParameterType,
SQLULEN ColumnSize,
SQLSMALLINT DecimalDigits,
SQLPOINTER ParameterValuePtr,
SQLLEN BufferLength,
SQLLEN * StrLen_or_IndPtr);
-
ParameterValuePtr: 指向一個有人口的SQL_SS_VECTOR_STRUCT -
ColumnSize:輸入參數被忽略。 對於輸出參數與執行時資料情境,請指定總向量大小:sizeof(SQL_SS_VECTOR_STRUCT)+(浮點 陣列大小) -
DecimalDigits:輸入參數被忽略。 對於輸出參數與執行時資料情境,請指定向量基底類型 -
BufferLength:≥sizeof(SQL_SS_VECTOR_STRUCT)+ (維度 *sizeof(float)) -
*StrLen_or_IndPtr: 必須包含相同的總大小
範例(原生 向量):
float values[3] = {1.0f, 2.0f, 3.0f};
SQL_SS_VECTOR_STRUCT vec;
SQLLEN cb;
vec.dimension = 3;
vec.type = 0; /* float32 */
vec.data.f32 = values;
cb = sizeof(vec) + sizeof(values);
SQLBindParameter(
hStmt, 1, SQL_PARAM_INPUT, SQL_C_SS_VECTOR, SQL_SS_VECTOR, 0, 0, &vec, cb, &cb);
SQLBindParameter 的 NULL 處理
應用程式可透過任一支援方式指示 NULL 向量:
設定
*StrLen_or_IndPtr為SQL_NULL_DATA,並將NULL作為ParameterValuePtr전달提供一個
SQL_SS_VECTOR_STRUCT:維度集合類型 =
float32data.f32=NULL
SQLPutData
驅動程式支援 SQLPutData 向量參數,並具備以下限制條件:
你必須在第一次通話時提供整個向量。
驅動程式不支援分塊或增量向量傳輸。
NULL處理遵循與SQLBindParameter相同的規則。典型通話:
SQLRETURN SQLPutData(
SQLHSTMT StatementHandle,
SQLPOINTER DataPtr,
SQLLEN StrLen_or_Ind);
-
DataPtr: 指向一個有人口的SQL_SS_VECTOR_STRUCT -
StrLen_or_Ind:sizeof(SQL_SS_VECTOR_STRUCT)+ (維度 *sizeof(float))
範例(原生 向量):
std::vector<float> floatArray = { 1.0f, 2.0f, 3.0f };
SQL_SS_VECTOR_STRUCT vectorValue = {0};
vectorValue.type = SQL_VECTOR_TYPE_FLOAT32;
vectorValue.dimension = (SQLUSMALLINT)floatArray.size();
vectorValue.data.f32 = floatArray.data();
// Tell ODBC this parameter will be supplied at execution time
SQLLEN cbVectorLen = SQL_LEN_DATA_AT_EXEC(
(SQLLEN)(sizeof(SQL_SS_VECTOR_STRUCT) + floatArray.size() * sizeof(float))
);
// Optional token to identify which parameter needs data
SQLPOINTER token = (SQLPOINTER)1;
// Bind as DATA_AT_EXEC: BufferLength is 0, value pointer can be a token
SQLRETURN rc = SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_SS_VECTOR, SQL_SS_VECTOR, 0, 0, token, 0, &cbVectorLen);
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
// handle error
}
rc = SQLExecute(hStmt);
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO && rc != SQL_NEED_DATA) {
// handle error
}
SQLPOINTER pParamToken = NULL;
rc = SQLParamData(hStmt, &pParamToken);
if (rc == SQL_NEED_DATA) {
// Provide entire vector in first SQLPutData call (no chunking)
rc = SQLPutData(
hStmt,
(SQLPOINTER)&vectorValue,
(SQLLEN)(sizeof(SQL_SS_VECTOR_STRUCT) + floatArray.size() * sizeof(float))
);
if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) {
// handle error
}
// Finalize parameter transfer
rc = SQLParamData(hStmt, &pParamToken);
}
描述符元資料
啟用向量支援後,Microsoft ODBC SQL Server 驅動程式會透過標準 ODBC 描述符 API 揭露向量元資料。 應用程式可以使用描述符資訊來發現向量結構細節、計算緩衝區大小,並正確配置參數與結果集的綁定。
向量的描述符欄位值
下表總結了 SQL Server 向量 欄位與參數的描述符欄位值。
| 描述項欄位 | 價值觀 | Description |
|---|---|---|
SQL_DESC_TYPE |
SQL_SS_VECTOR (-156) |
基礎 SQL 資料型別識別碼 |
SQL_DESC_CONCISE_TYPE |
SQL_SS_VECTOR |
簡明 SQL 資料型別 |
SQL_DESC_TYPE_NAME |
vector |
SQL 型別名稱 |
SQL_DESC_LOCAL_TYPE_NAME |
vector |
驅動程式本地類型名稱 |
SQL_DESC_LENGTH |
sizeof(SQL_SS_VECTOR_STRUCT) + (dimension * sizeof(float)) |
向量值的邏輯大小 |
SQL_DESC_OCTET_LENGTH |
與 SQL_DESC_LENGTH 相同 |
以位元組為單位的物理大小 |
SQL_DESC_PRECISION |
與 SQL_DESC_LENGTH 相同 |
用於報告向量大小 |
SQL_DESC_SCALE |
SQL_VECTOR_TYPE_FLOAT32 |
向量基底元素類型 |
SQL_DESC_DISPLAY_SIZE |
dimension * VECTOR_FLOAT32_TO_CHAR_JSON_MAX_SIZE |
最大 JSON 顯示長度 |
SQL_DESC_FIXED_PREC_SCALE |
SQL_FALSE |
向量沒有固定的精度或刻度 |
SQL_DESC_NULLABLE |
SQL_NULLABLE |
向量欄位允許 NULL 值 |
SQL_DESC_NUM_PREC_RADIX |
0 |
非數字型 |
SQL_DESC_SEARCHABLE |
SQL_PRED_NONE |
無法用於謂詞 |
SQL_DESC_UNSIGNED |
SQL_TRUE |
元素類型為無符號 |
SQL_DESC_AUTO_UNIQUE_VALUE |
SQL_FALSE |
無自動唯一性 |
SQL_DESC_CASE_SENSITIVE |
SQL_FALSE |
不區分大小寫 |
SQL_DESC_UPDATABLE |
SQL_ATTR_READWRITE_UNKNOWN |
更新性未知 |
SQLDescribeCol
當你呼叫 SQLDescribeCol 針對 向量 欄位時:
-
DataType是SQL_SS_VECTOR -
ColumnSize匹配SQL_DESC_PRECISION -
DecimalDigits是0(基底型態指示器,非數值刻度) -
Nullable是SQL_NULLABLE
報告的欄位大小代表本地向量有效載荷大小: sizeof(SQL_SS_VECTOR_STRUCT) +(維度 * sizeof(float))
SQLDescribeParam
當你使用 SQLDescribeParam 作為 向量 參數時:
-
DataType是SQL_SS_VECTOR -
ColumnSize等於本地向量有效載荷大小 -
DecimalDigits是0(基底型態指示器,非數值刻度) -
Nullable是SQL_NULLABLE
這些資訊讓應用程式能在綁定前正確分配參數緩衝區。
SQLColAttribute
使用
SQLColAttribute(hstmt, ColumnNumber, SQL_DESC_OCTET_LENGTH, ...)取得向量有效載荷的精確位元組長度。SQL_DESC_LENGTH且SQL_DESC_PRECISION可能帶有驅動程式特定的數值。 位元組計數方面,建議使用SQL_DESC_OCTET_LENGTH。-
NULL處理:當欄位為NULL時,SQLColAttribute(或與StrLen_or_IndPtr使用的SQLBindCol)返回SQL_NULL_DATA。 在使用回傳長度或緩衝區之前,請先確認SQL_NULL_DATA。
-
批量副本(BCP)
你可以像其他資料類型一樣,透過 BCP 檔案和 bcp_bind API 批量匯入和匯出向量欄位。 目前,向量匯入與匯出僅支援原生格式(SQLVECTOR)或 變數格式 (SQLBINARY),但不支援字元格式。 不支援 向量 型別與字元型別的轉換。
關於 向量的類型標記、預設前綴長度及預設欄位長度的更多資訊,請參閱 檔案儲存類型、 前綴長度與 欄位長度。
bcp_gettypename
當你用 bcp_gettypename 來取得 向量的 SQL 型別名稱時,它會回傳 BCP 型別的標記(SQLVECTOR)和 "vector"。
bcp_bind
用 bcp_bind 來批量插入程式變數到 向量 欄位。
典型通話:
RETCODE bcp_bind (
HDBC hdbc,
LPCBYTE pData,
INT cbIndicator,
DBINT cbData,
LPCBYTE pTerm,
INT cbTerm,
INT eDataType,
INT idxServerCol);
-
pData: 若cbIndicator為零,則包含一個指向SQL_SS_VECTOR_STRUCT資料的指標,其中有 浮點數 陣列資料(vectorStruct.data.f32欄位)。 若cbIndicator非零,指示器會直接出現在記憶體中的資料前面。 因此pData,會指向一個緩衝區,該緩衝區首先是長度cbIndicator指示字節,接著是向量結構。 -
cbData:若提供,值必須恰好等於 -sizeof(SQL_SS_VECTOR_STRUCT)+ (sizeof(float32)* 維度)。 若不行,則發生錯誤。 -
eDataType:SQLVECTOR或SQLBINARY
當你透過 將資料匯入向量欄位 bcp_bind時,設 eDataType 為 SQLVECTOR 或 SQLBINARY。 在這兩種情況下,你都必須以 SQL_SS_VECTOR_STRUCT 的形式提供資料。
疑難排解與秘訣
- 如果
SQLGetTypeInfo沒有列出VECTOR,就退回用 varchar 來儲存向量。