Go и Oracle
На работе произошло кое-что необычное: вдруг пригодились знания Гоу. Не то чтобы нельзя было написать требуемое на другом языке, но нужно было быстро и на чём-то компилируемом. На Си всё работало бы значительно быстрее, но писалось бы неделю или более, поэтому я написал прототип на Гоу, управившись всего за два дня. Скорость работы оказалась выше ожидаемой и теперь, как кажется, прототип уже начинает превращаться в продукт.
Проблемы начались, когда я попытался подключиться из прототипа к СУБД «Оракл» (такое было условие задачи). Сначала я, как и наверное многие до меня, нашёл драйвер 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, т. е. они конвертируются из любой другой автоматически. Мне их приходится конвертировать обратно, но скорость чтения настолько велика (на порядок быстрее ПХП), что меня это пока не волнует.
Евгений, а зачем в наше время нужно хранить данные не в UTF-8 (Unicode), и в большинстве случаев создавать себе проблемы?
и еще N вариантов зачем и почему нужен 1251.
Комментарий для Раиль:
Вот Багир всё очень точно рассказал. Например, скорость поиска при хранении CP1251 вместо UTF-8 выросла в два раза (видимо, просто потому, что русскоязычный текст стал вдвое компактнее).
«На Си было бы значительно быстрее, поэтому я написал прототип именно на Гоу, управившись всего за два дня.» Непонятное предложение. На Си было бы быстрее написать, или программа на Си работала бы быстрее? Как с этим связан выбор Go?
Комментарий для Прохожий:
Да, и правда. Писал, едучи в такси, поэтому невнятно вышло )