Go и Oracle

На работе произошло кое-что необычное: вдруг пригодились знания Гоу. Не то чтобы нельзя было написать требуемое на другом языке, но нужно было быстро и на чём-то компилируемом. На Си всё работало бы значительно быстрее, но писалось бы неделю или более, поэтому я написал прототип на Гоу, управившись всего за два дня. Скорость работы оказалась выше ожидаемой и теперь, как кажется, прототип уже начинает превращаться в продукт.

прототип (60.56КиБ)

Проблемы начались, когда я попытался подключиться из прототипа к СУБД «Оракл» (такое было условие задачи). Сначала я, как и  наверное многие до меня, нашёл драйвер go-oci8. Очень не рекомендую его использовать, если у вас задача чуть сложнее, чем «выбрать пару чисел из запроса».

Для начала, проблема возникла с кодировкой. У нас в базе используется кодовая таблица 1251. Сначала (тут я сам дурак) мне показалось, что драйвер не учитывает кодировку из переменных откружения (проблема оказалась в 11-й строчке примера (который идёт с драйвером), где очищалась переменная NLS_LANG), поэтому пришлось соорудить патч:

charset := C.CString(charset_dsn)
defer C.free(unsafe.Pointer(charset))

env := new(C.OCIEnv)
rv = C.OCIEnvNlsCreate(
    (**C.OCIEnv)(unsafe.Pointer(&env)),
    C.OCI_DEFAULT | C.OCI_OBJECT,
    nil, nil, nil, nil, 0, nil, 0, 0,
)
charset_id := C.OCINlsCharSetNameToId(unsafe.Pointer(env), (*C.oratext)(unsafe.Pointer(charset)))

rv = C.OCIEnvNlsCreate(
    (**C.OCIEnv)(unsafe.Pointer(&conn.env)),
    C.OCI_DEFAULT | C.OCI_OBJECT | C.OCI_THREADED | C.OCI_NO_MUTEX,
    nil, nil, nil, nil, 0, nil,
    charset_id, charset_id,
)

Этот код должен работать вместо OCIEnvInit, если нужно использовать кодировку. Но, повторюсь, это проблема не драйвера, просто этот тот случай, когда «ложечки нашлись, а осадок остался».

Потом оказалось, что в драйвере нет превыборки (prefetch), из-за чего чтение из таблицы было очень медленным. Чашу терпения же переполнило отстутствие работы с типом CLOB — при попытке получить данные этого типа размером более 4000 байт, драйвер сообщил, что нехватает буфера.

Я подумал, что постоянно решать проблемы драйвера — не мой путь и нашёл прекрасный Goracle, чуть более сложный, но обладающий всеми мыслимыми возможностями, порт с пайтонячего драйвера, написанного на Си.

Единственная неприятность — драйвер все строки возвращает в кодировке UTF-8, т. е. они конвертируются из любой другой автоматически. Мне их приходится конвертировать обратно, но скорость чтения настолько велика (на порядок быстрее ПХП), что меня это пока не волнует.

Поделиться
Отправить
2014   googlego   oracle
5 комментариев
Раиль

Евгений, а зачем в наше время нужно хранить данные не в UTF-8 (Unicode), и в большинстве случаев создавать себе проблемы?

Bagir
  1. Производительность.
  2. Экономия памяти.
  3. Исторически сложившаяся ситуация в проекте.
    и еще N вариантов зачем и почему нужен 1251.
Евгений Степанищев (bolknote.ru)

Комментарий для Раиль:

Евгений, а зачем в наше время нужно хранить данные не в UTF-8 (Unicode), и в большинстве случаев создавать себе проблемы?

Вот Багир всё очень точно рассказал. Например, скорость поиска при хранении CP1251 вместо UTF-8 выросла в два раза (видимо, просто потому, что русскоязычный текст стал вдвое компактнее).

Прохожий

«На Си было бы значительно быстрее, поэтому я написал прототип именно на Гоу, управившись всего за два дня.» Непонятное предложение. На Си было бы быстрее написать, или программа на Си работала  бы быстрее? Как с этим связан выбор Go?

Евгений Степанищев (bolknote.ru)

Комментарий для Прохожий:

Да, и правда. Писал, едучи в такси, поэтому невнятно вышло )

Популярное