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, т.е. они конвертируются из любой другой автоматически. Мне их приходится конвертировать обратно, но скорость чтения настолько велика (на порядок быстрее ПХП), что меня это пока не волнует.
3 февраля 2014 08:07

Раиль (инкогнито)
3 февраля 2014, 08:44

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

Bagir (инкогнито)
3 февраля 2014, 08:58

1. Производительность.
2. Экономия памяти.
3. Исторически сложившаяся ситуация в проекте.
и еще N вариантов зачем и почему нужен 1251.

Евгений Степанищев (bolknote.ru)
3 февраля 2014, 09:25, ответ предназначен Раилю

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

Прохожий (инкогнито)
3 февраля 2014, 10:18

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

Евгений Степанищев (bolknote.ru)
3 февраля 2014, 10:37, ответ предназначен Прохожему

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

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML:

Кому бы вы хотели ответить (или кликните на его аватару)