この記事では、バージョン 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 (SQLGetDataやSQLBindColなど) は、ベクター列をSQL_C_SS_VECTORまたはSQL_C_BINARYとして返すことができます。SQL_C_SS_VECTORは、型指定されたコンパクトな形式でベクターを返します。SQL_C_BINARYは varbinary ペイロードを返します。入力またはパラメーターバインドの場合、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すると、ベクター列は 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_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)+ 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_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を使用して、指定した向き (次、前、絶対、相対、ブックマーク) に従って行セットをフェッチします。 ドライバーは、ベクター データをアプリケーション バッファーに正しくコピーします。
- 一般的な呼び出し:
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_IndPtrをSQL_NULL_DATAに設定し、次のようにNULL渡しますParameterValuePtrSQL_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列のを呼び出すとき:
-
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) または 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を使用してデータをベクター列にインポートする場合は、eDataTypeをSQLVECTORまたはSQLBINARYに設定します。 どちらの場合も、 SQL_SS_VECTOR_STRUCTの形式でデータを提供する必要があります。
トラブルシューティングとヒント
-
SQLGetTypeInfoVECTORが一覧表示されない場合は、ベクターを varchar として格納することにフォールバックします。