次の方法で共有


ベクター データ型 (ODBC)

この記事では、バージョン 18.6.1.1 以降の Microsoft ODBC Driver for SQL Server によって実装された ベクター SQL データ型について説明します。 このドキュメントでは、 ベクトルに対する Microsoft ドライバーの動作の概要を説明し、使用ガイダンス、API 固有の注意事項、およびコード スニペットについて説明します。 ベクター データ型の概要については、ベクター データ に関するページを参照してください。

概要

Microsoft ODBC Driver for SQL Server では、 ベクター データ型がネイティブにサポートされています。 アプリケーションは、機械学習と AI ワークロードでよく使用される固定次元の数値埋め込みを効率的に格納、取得、および処理できます。 ドライバーは、標準の ODBC API と C データ型を通じてベクターサポートを公開します。 アプリケーションは、既存の ODBC ワークフローを変更することなく、SQL Server ベクター列と相互運用できます。

適用対象: Microsoft ODBC Driver for 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_VECTORまたはSQL_C_BINARYとして返すことができます。 SQL_C_SS_VECTOR は、型指定されたコンパクトな形式でベクターを返します。 SQL_C_BINARYvarbinary ペイロードを返します。

    • 入力またはパラメーターバインドの場合、Microsoft ドライバー (18.6.1.1 vectorTypeSupport=v1) では、 SQL_C_SS_VECTORSQL_C_BINARYの両方がサポートされます。 SQL_C_SS_VECTOR は、型指定されたコンパクトな入力バインドを提供します。 SQL_C_BINARY は同等であり、移植可能です。 ドライバーでペイロードをネイティブ SQL_C_SS_VECTOR型として扱う場合は、を使用します。

    • vectorTypeSupport=offすると、ベクター列は JSON 配列を含む varchar(max) として表示されます。

アプリケーションでは、ベクター固有の型を使用する前に、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 ガイダンス

このセクションでは、バッファー レイアウトの要件、 NULL 処理、サポートされるデータ表現など、ODBC API が SQL Server ベクター データと対話する方法について説明します。 すべての動作は、 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) + float 配列サイズ (次元 * 4) です。

バッファー レイアウトの期待値

非連続バッファー (推奨)

  • アプリケーションは、行ごとに 1 つの SQL_SS_VECTOR_STRUCT を割り当てます。
  • アプリケーションは、 data.f32にメモリを割り当てます。
  • ドライバーは、ベクター メタデータを設定し、指定された float バッファーに要素の値を書き込みます。
    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());

連続するバッファー

  • アプリケーションは 1 つのバッファーを割り当て、それに応じて 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_IndPtrSQL_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_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) + float 配列サイズ (次元 * 4) です。

チャンク取得はサポートされていません。 ベクター全体を 1 回の呼び出しで取得する必要があります。

例 (ネイティブ ベクター):

    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_IndPtrSQL_NULL_DATAに設定し、バッファーを使用しません。 ベクトルの内容にアクセスする前に、必ずインジケーターを確認してください。

ベクター列の読み取りと行フェッチの動作については、SQLFetchSQLFetchScrollで詳しく説明します (フェッチ セマンティクスと配列フェッチの例については、これらの 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を使用して、指定した向き (次、前、絶対、相対、ブックマーク) に従って行セットをフェッチします。 ドライバーは、ベクター データをアプリケーション バッファーに正しくコピーします。

  • 一般的な呼び出し:
    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) + (float 配列サイズ)
  • 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_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 Driver for 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 です
  • ColumnSizeSQL_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) または varbinary (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 が 0 の場合は、データへのポインター SQL_SS_VECTOR_STRUCT 含み、その中に float 配列データが含まれます (フィールドvectorStruct.data.f32 )。 cbIndicatorが 0 以外の場合、インジケーターはメモリ内のデータの直前に表示されます。 したがって、 pData は、最初に cbIndicator バイトの長さのインジケーターを持ち、その後にベクター構造体が続くバッファーを指します。
  • cbData: 指定する場合は、 sizeof(SQL_SS_VECTOR_STRUCT) + (sizeof(float32) * ディメンション) と正確に等しい値を指定する必要があります。 そうでない場合は、エラーが発生します。
  • eDataType: SQLVECTOR または SQLBINARY

bcp_bindを使用してデータをベクター列にインポートする場合は、eDataTypeSQLVECTORまたはSQLBINARYに設定します。 どちらの場合も、 SQL_SS_VECTOR_STRUCTの形式でデータを提供する必要があります。

トラブルシューティングとヒント

  • SQLGetTypeInfo VECTORが一覧表示されない場合は、ベクターを varchar として格納することにフォールバックします。