Поделиться через


Тип векторных данных (ODBC)

В этой статье описан векторный тип данных SQL, реализованный драйвером Microsoft ODBC для SQL Server, начиная с версии 18.6.1.1. В этом документе описано поведение драйвера Майкрософт для вектора и предоставляет рекомендации по использованию, заметки для API и фрагменты кода. Общие сведения о типах векторных данных см. в разделе "Тип данных Vector".

Обзор

Драйвер Microsoft ODBC для SQL Server изначально поддерживает тип векторных данных. Приложения могут эффективно хранить, извлекать и обрабатывать числовые внедрения фиксированного измерения, часто используемые в рабочих нагрузках машинного обучения и искусственного интеллекта. Драйвер предоставляет векторную поддержку через стандартные API ODBC и типы данных C. Приложения могут взаимодействовать с столбцами векторов SQL Server, не изменяя существующие рабочие процессы ODBC.

Применяется к: Драйвер Microsoft ODBC для SQL Server 18.6.1.1 и более поздних версий.

Для драйвера Майкрософт (18.6.1.1.1) поддержка векторов отключена по умолчанию и должна быть явно включена.

Представление нативного C

Если включена поддержка векторов, векторные столбцы обмениваются с помощью типизированной структуры C с именем SQL_SS_VECTOR_STRUCT.

    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 полезную нагрузку.

    • Для ввода или привязки параметров драйвер Майкрософт (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. Приложения могут использовать этот формат для сценариев взаимодействия низкого уровня. Буфер указателя данных может быть непрерывным или несмежным по отношению к адресу памяти структуры.

Руководство по API ODBC

В этом разделе описывается взаимодействие API ODBC с данными вектора 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());

Обработка NULL для SQLBindCol

Если значение столбца равно NULL, драйвер устанавливает *StrLen_or_IndPtrSQL_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);

Обработка NULL для SQLGetData

Если значение столбца равно NULL, драйвер устанавливает *StrLen_or_IndPtrSQL_NULL_DATA и не заполняет буфер. Всегда проверяйте индикатор перед доступом к содержимому вектора.

Замечание

Поведение чтения и извлечения строк для векторных столбцов подробно описано SQLFetch в разделе и SQLFetchScroll (см. эти ссылки на API для получения семантики и примера получения массива).

SQLFetch

Для получения следующей строки и корректной обработки всех привязанных столбцов используется SQLFetch.

  • Типичный вызов:
    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) + (размер массива с плавающей запятой )
  • 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);

Обработка NULL для SQLBindParameter

Приложения могут указывать вектор 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 предоставляет метаданные вектора через стандартные API дескриптора ODBC. Приложения могут использовать сведения о дескрипторе для обнаружения сведений о схеме векторов, размеров буфера вычислений и правильной настройки привязок для параметров и результирующих наборов.

Значения полей дескриптора для вектора

В следующей таблице перечислены значения полей дескриптора для столбцов и параметров векторов 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 Vector не имеет фиксированной точности и масштабирования
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 равно нулю, содержит указатель на данные SQL_SS_VECTOR_STRUCT, которые содержат массив данных с плавающей запятой в поле . Если 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.