Каков наилучший способ чтения всего LOB с использованием ODBC? - PullRequest
0 голосов
/ 25 апреля 2018

Чтение во всем большом объекте, размер которого вы не знаете заранее (без максимального выделения + копии), должно быть довольно распространенной проблемой, но поиск хорошей документации и / или примеров «правильного» способа сделать это доказал совершенно безумный для меня.

Я боролся с SQLBindCol, но не мог найти хорошего способа заставить его работать. SQLDescribeCol и SQLColAttribute возвращают метаданные столбца, которые, по-видимому, являются значением по умолчанию или верхней границей размера столбца, а не фактическим размером текущего большого объекта. В итоге я остановился на следующем:

1) Поместите все / все столбцы больших объектов в столбцы с наибольшим номером в инструкции SELECT

2) SQLPrepare утверждение

3) SQLBindCol любые более ранние столбцы без больших объектов, которые вы хотите

4) SQLExecute утверждение

5) SQLFetch строка результатов

6) SQLGetData в столбце больших объектов с буфером размера 0, чтобы запросить его фактический размер

7) Выделите буфер достаточно большой, чтобы вместить ваш LOB

8) SQLGetData снова в столбце больших объектов с выделенным буфером правильного размера на этот раз

9) Повторите шаги 6-8 для каждого последующего столбца большого объекта

10) Повторите шаги 5-9 для всех остальных строк в наборе результатов

11) SQLCloseCursor когда вы закончите с набором результатов

Это, кажется, работает для меня, но также кажется довольно сложным.

Возвращаются ли вызовы SQLGetData на сервер или просто обрабатываются результаты, уже отправленные клиенту?

Есть ли какие-либо ошибки, когда сервер и / или клиент откажутся обрабатывать очень большие объекты таким образом (например, превышен порог некоторого размера, поэтому вместо этого они генерируют ошибку)?

Самое главное, есть ли лучший способ сделать это?

Спасибо!

Ответы [ 3 ]

0 голосов
/ 28 апреля 2018

Чтобы избежать максимального выделения, создания дополнительной копии и повышения эффективности:

Получение первого размера - неплохой подход - для выполнения

* 1004 практически не требуется дополнительного времени.*

Затем выполните выделение и фактически получите большой двоичный объект.

Если имеется несколько столбцов BLOB, захватите все длины за один проход:

SELECT LENGTH(blob1), LENGTH(blob2), ... FROM ...

В MySQL длинаBLOB или TEXT легко доступен перед байтами.Но, даже если он должен прочитать столбец, чтобы получить длину, думайте об этом как о простом заполнении кэша.То есть общее время не сильно пострадало в любом случае.

0 голосов
/ 04 мая 2018

Я вижу несколько улучшений, которые нужно сделать.

  1. Если вам нужно выделить буфер, то вы должны сделать это один раз для всех записей и столбцов.Таким образом, вы можете использовать метод, предложенный @RickJames, улучшенный с помощью MAX, например:

    ВЫБЕРИТЕ МАКС (ДЛИНА (blob1)) КАК max1, МАКС (ДЛИНА (blob2)) КАК max2, ...

Вы можете использовать max1 и max2 для предварительного выделения буферов или, возможно, только самый большой для всех столбцов.

Длина буфера, возвращаемого в 1., может быть слишком большой для вашего приложения.Вы можете решить во время выполнения, насколько большим будет буфер.В любом случае, SQLGetData предназначен для многократного вызова для каждого столбца.Просто вызвав его снова с тем же номером столбца, он получит следующий фрагмент.Количество доступных байтов будет сохранено в том месте, куда указывает StrLen_or_IndPtr (последний аргумент).И это число будет уменьшаться после каждого вызова с количеством извлеченных байтов.

И, конечно же, при каждом вызове на сервер будут передаваться туда и обратно, потому что цель всего этого - не дать драйверу получить большечем приложение может обработать.

Трюк с передачей NULL в качестве указателя буфера для получения длины в этом случае запрещен, отметьте SQLGetData в Документах Microsoft.

Однако вы могли бывыделить минимальный буфер, скажем, 8 байтов, передать его и его длину.Функция вернет количество записанных байтов, 7 в нашем случае, потому что функция добавляет нулевой символ, и установит в StrLen_or_IndPtr количество оставшихся байтов.Но вам, вероятно, это не понадобится, если вы выделите буфер, как описано выше.

Примечание: LOB должны находиться в конце списка выбора и должны выбираться в этом порядкеточно.

0 голосов
/ 26 апреля 2018

SQLGetData

SQLGetData получить результат уже извлеченного результата. Например, если у вас SQLFetch первая строка вашей таблицы, SQLData вернет вам первую строку. Он используется, если вы не знаете, можете ли вы SQLBindCol получить результат.

Но то, как он работает, зависит от вашего драйвера и не описано в стандартах. Если ваша база данных является базой данных SQL, курсор не может вернуться назад, поэтому результат может оставаться в памяти.

Запрос большого объекта

Сервер может отказать в обработке большого объекта в соответствии со стандартом сервера и вашим драйвером ODBC . Это не описано в стандарте ODBC .

...