Пишу, по большей части, про историю, свою жизнь и немного про программирование.

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

Ctrl →DBF → text
5 комментариев
Раиль 2014

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

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

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

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

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

Прохожий 2014

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

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

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

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