共用方式為


向量資料型態(ODBC)

本文說明了自 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(例如 SQLGetDataSQLBindCol)可以返回 向量 欄位,表示為 SQL_C_SS_VECTORSQL_C_BINARY或 。 SQL_C_SS_VECTOR 以緊湊且具類型的形式回傳向量。 SQL_C_BINARY 回傳一個 變異型 有效載荷。

    • 對於輸入或參數綁定,Microsoft 驅動程式(18.6.1.1 版本,包含 vectorTypeSupport=v1)同時支援 SQL_C_SS_VECTORSQL_C_BINARYSQL_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_VECTORSQL_C_BINARY

  • TargetValuePtr:指向一個包含SQL_SS_VECTOR_STRUCT陣列的的指標,當TargetTypeSQL_C_SS_VECTOR時;否則,指向一個大小為StrLen_or_IndPtr值的緩衝區的指標。

  • BufferLengthsizeof(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 且不會填入緩衝區。 在存取向量內容物前,務必先檢查指示器。

備註

向量欄位的讀取與列擷取行為在SQLFetchSQLFetchScroll中有詳細說明(參見 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_VECTORSQL_C_BINARY

  • TargetValuePtr:指向一個包含SQL_SS_VECTOR_STRUCT陣列的的指標,當TargetTypeSQL_C_SS_VECTOR時;否則,指向一個大小為StrLen_or_IndPtr值的緩衝區的指標。

  • BufferLengthsizeof(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 且不會填入緩衝區。 在存取向量內容物前,務必先檢查指示器。

備註

向量欄位的讀取與列擷取行為在SQLFetchSQLFetchScroll中有詳細說明(參見 API 參考文獻中的擷取語法與陣列擷取範例)。

SQLFetch

SQLFetch 來擷取下一列,並正確地將任何綁定在 SqlVector 的欄位實現。

  • 典型通話:
    SQLRETURN SQLFetch(
     SQLHSTMT     StatementHandle);

在標準迴圈中呼叫 SQLFetchSqlVector 欄位已透過 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_IndPtrSQL_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_Indsizeof(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 針對 向量 欄位時:

  • DataTypeSQL_SS_VECTOR
  • ColumnSize 匹配 SQL_DESC_PRECISION
  • DecimalDigits0 (基底型態指示器,非數值刻度)
  • NullableSQL_NULLABLE

報告的欄位大小代表本地向量有效載荷大小: sizeof(SQL_SS_VECTOR_STRUCT) +(維度 * sizeof(float)

SQLDescribeParam

當你使用 SQLDescribeParam 作為 向量 參數時:

  • DataTypeSQL_SS_VECTOR
  • ColumnSize 等於本地向量有效載荷大小
  • DecimalDigits0 (基底型態指示器,非數值刻度)
  • NullableSQL_NULLABLE

這些資訊讓應用程式能在綁定前正確分配參數緩衝區。

SQLColAttribute

  • 使用 SQLColAttribute(hstmt, ColumnNumber, SQL_DESC_OCTET_LENGTH, ...) 取得向量有效載荷的精確位元組長度。 SQL_DESC_LENGTHSQL_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) * 維度)。 若不行,則發生錯誤。
  • eDataTypeSQLVECTORSQLBINARY

當你透過 將資料匯入向量欄位 bcp_bind時,設 eDataTypeSQLVECTORSQLBINARY。 在這兩種情況下,你都必須以 SQL_SS_VECTOR_STRUCT 的形式提供資料。

疑難排解與秘訣

  • 如果 SQLGetTypeInfo 沒有列出 VECTOR,就退回用 varchar 來儲存向量。