Как стать автором
Обновить

Комментарии 21

с Oracle каждый раз нас ждут какие-то сюрпризы. Проницательный читатель сразу заметит, что "руки у нас кривые" и мы "попросту не умеем его готовить"

Отнюдь. Старый тяжелый legacy движок, абсолютно недружественный к пользователю, рассчитанный на постоянное присутствие DBA в системе.

Он разве не с DBA сразу поставляется? :)
говорят, что администратор оракл, получивший все сертификаты и сдавший все экзамены, может sql-запросом убить человека, зная только его IP
? :)
Я этот лимит встречал на древней системе, Оракл11+Delphi. Только вроде приложение не писало текст ошибки, а просто не сохраняло. Лимит узнали, только когда полезли в базу.
Но там было дело в кириллице.
Не уверен, что понимаю о каком лимите идет речь. Нужно просто постоянно явно писать, что длина varchar2 в символах, а не байтах и по данным Oracle лучше значение по умолчанию для этой настройки не менять. И это печалит и, скорее всего, является постоянным источником ошибок для систем с хранением текстов в Unicode'e.
А ещё нужно помнить, что максимальная длина поля varchar2(4000 byte). Если получится больше — ошибка. Varchar2(4000 char) также ограничена 4000 байт. Было так весело это узнавать в свое время.
Спасибо. Проверю. У нас правда макс 1тыс. вроде (и то не уверен, что такое не в clob'e храним), но, блин, снова та же диллема: Unicode и размер в байтах )))))

Varchar2 по историческим причинам предназначен для хранения строк в какой-либо однобайтной кодировке, возможность хранить их в utf-8, скорее, fallback. Для строк в чем угодно используйте nvarchar. Если, конечно, не подменили кодировку хранения nvarchar не на Unicode при создании базы ;)

Насколько я вижу-знаю, это не так: nvarchar (а точнее nvarchar2) — это некий специальный тип, которые появился до unicode (данные со stackoverflow, не проверял), а сейчас это нечто маргинальное для хранения данных в кодировке UTF-16 (AL16UTF16), в то время, как в varchar2 по умолчанию данные в кодировке UTF-8 (AL32UTF8).

То, о чем Вы пишите — 100% в MS SQL'е, где именно nvarchar типы мы, например, и используем, но не в Oracle. Кодировка для varchar2 по-умолчанию в Unicode'ом Oracle'e — это UTF-8 (AL32UTF8).

Опять же, по данным stackoverflow не все PLSQL ф-ии совместимы с nvarchar2 (не то, чтобы это было таким уж нужным, но все же ...).

Да, я тоже, за все ~20 лет работы с базами Oracle ни разу не видел ни одной Production системы, где бы использовались N% типы. Т.е. они как бы есть, все про них знают, вопросы про них есть в сертификационных экзаменах, альтернативную кодировку указывают при каждом создании новой базы, но… Никто не пользуется. Потому что нет нужды. Всё и так хорошо сохраняется в обычные типы и Unicode корректно работает… При условии, конечно, семантики CHAR, о чем и статья.

IMHO тема разобрана ну очень поверхностно. Имело бы смысл расписать IMHO как минимум что:


  • после выполнения ALTER TABLE с указанием "CHAR" для колонки, только новые значения (вставки/обновления) примут новый параметр и станут "Unicode-compatibe" с точки зрения длины сохраняемой строки — существующие строки не будут затронуты. И для того чтобы и их сделать такими же, требуется перестройка таблицы (ALTER TABLE MOVE, CTAS, DBMS_REDEFINITION, EXP/IMP), а это уже совсем другая история, порой очень большая и сложная (поэтому полезно думать заранее про семантику Byte/Char, в момент создания таблицы)
  • именно для того чтобы "не думать заранее", а иногда это и просто невозможно, если продукт не ваш и скрипты создания таблиц трогать нельзя — на уровне экземпляра базы выставляется INIT.ORA параметр nls_length_semantics=char, и тогда база сама дописывает во все определения полей семантику CHAR
  • есть множество зарегистрированных багов (на MOS) с семантикой CHAR — особенно со всякими вложенным типами (типы поля NESTED TABLE и TYPE, это когда "таблица в таблице" — в колонке содержится массив полей)
  • доходит до того что при выставленом параметре nls_length_semantics=CHAR, например, невозможно проимпортировать дамп базы (схемы) с помощью Data Pump — трюк заключается в выставлении nls_length_semantics=byte, затем импорт, и опять возвращение nls_length_semantics=char
  • тут кстати глубина глюков настолько велика, что хоть и параметр nls_length_semsntics динамический (ALTER SYSTEM), все равно необходима перезагрузка экземпляра чтобы импорт заработал

Это из того что сразу вспомнилось.
Еще можно упомянуть что при "разборе полётов", почему у нас "кракозябры" вместо русских букв / национальных символов типа всяких "умляутов", полезно использовать функцию DUMP() для строки и для символов — позволяет увидеть, что же реально сохранено в базе, посимвольно, а не то что глаза видят.


Ну и последнее — замечание что "во всех базах все ОК, а вот в Оракле приходится разбираться" — ну да, эта вся тема с семантикой — её просто нужно знать, что есть такая особенность, это просто опыт. Х

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

Что это за бред в первом пункте? Что конкретно в существующих строках хотели менять? По вашему каждое varchar2 поле каждой строки хранит свой nls_length_semantics?!


INIT.ORA

Вот прямо в INIT.ORA?!


есть множество зарегистрированных багов

Багов вообще множество в чем угодно, если ссылаетесь на что-то, то уж будьте любезны приводить хотя бы пару примеров.


доходит до того что при выставленом параметре nls_length_semantics=CHAR, например, невозможно проимпортировать дамп

Ой ли?!


все равно необходима перезагрузка экземпляра чтобы импорт заработал

Да ну?!

Я верно понял, что была тула, которую писал человек, который знал эту особенность Oracle (имхо, вы верно подметили, что эта особенность из-за необходимости поддержки обратной совместимости) и в какой-то момент кто-то другой, уже не знающий этой особенности решил оптимизировать данный тул и убрал дописывание char?
Если все так:
1. Исходный разработчик молодец, но ему стоило написать тест об этом.
2. Разработчик выполнявший рефакторинг решил исправить то, в чем, видимо, сам не особо разбирался
А по итогу во всем обвинили Oracle :-)
Хуже :) Это знают «все» кто Oracle only, или с него в мир реляционных баз пришел или… Просто это идет (немного?) в разрез всех других виденных баз и вызывает мягко говоря WTF удивление.
Вопрос не в том, что кто-то добавил или убрал char в синтаксис statement'ом. Вопрос в том, что это котрлогичное поведение которое ты не ожидаешь от базы (не буду про стоимость и пр.) и все это нужно «всего лишь» для совместимости, которая, возможна нужна не многим.

Это нечто такое простое и базовое, что я уверен знают далеко не все.

По поводу toolзы — скрипты были сгенерированы стандартным ПО (не самописным). Там видать эти «сюрпризы» знали :). Далее система развивалась, что-то изменялось-добавлялось (скрипты писались вручную). В части есть char, в части нет :) Потом провели расследование какого фига оно таки иногда падает. Нашли, вычистили. Решили поделиться опытом. Вдруг не мы одни такие. Мало ли…
все это нужно «всего лишь» для совместимости, которая, возможна нужна не многим.

Большое количество очень крупных клиентов с очень давних времен на Oracle с крайне важными данными, поэтому вопросы надежности и совместимости это наиболее важные вопросы. По этой причине очень-очень многие обновляются на новые версии очень неохотно и только после того как новые версии становятся достаточно стабильными. Даже платят огромные суммы за Extended support. Процесс накатки скриптов для Oracle тоже уже давным давно в серьезных системах отлажен и включает все необходимые настройки и параметры. Посмотрите, например, на огромные документы от SAP.

А можно не менять настройки базы, а поменять настройки своей сессии:
ALTER SESSION SET NLS_LENGTH_SEMANTICS="CHAR";
Можно, но что это меняет особо? Т.е. для меня главное, то нужно постоянно об этой особенности Oracle «помнить».

Oracle очень и очень гибок, у него огромное количество разнообразных параметров и настроек на всех уровнях всех подсистем, намного больше чем у MS SQL Server, DB2, Postgres и MySQL вместе взятых, что позволяет его подстроить так как необходимо конкретной системе. Естественно, что это требует хорошего знания как самого Oracle так и смежных систем. Это же не какой-нибудь SQLite. Не хотите ничего "помнить" — пользуйтесь excel или csv файликами.

Тут есть такая тонкость — если создание таблиц и вставка данных будет выполняться не в текущей сессии, а например Data Pump'ом — то ему Вы не выставите параметр с помощью ALTER SESSION. Во-первых это просто невозможно, т.к. Data Pump сам подключается к базе (сама утилита impdp или impdp.exe, из командной стоки, при запуске утилиты), а во-вторых, т.к. Data Pump — утилита серверная, он порождает т.н. воркеры (DP Workers, процессы DWnn). И именно воркеры уже создают таблицы, вставляют строки и тд. И очевидно, новые процессы сами присоединяются к базе, и им команду ALTER SESSION нужно «подсунуть». Так что Ваш комментарий нужно немного подправить и уточнить вот так: можно не менять параметр NLS_LENGTH_SEMANTICS на уровне всего экземпляра базы (через INIT.ORA), а выставлять на уровне сессии, через ALTER SESSION, из триггера. Суть — создаёте ONLOGON триггер, обвешиваете его проверками, чтобы срабатывал только на нужные сессии (например, на упомянутые воркеры Data Pump'а, фильтруя по V$SESSION.PROGRAM и V$SESSION.MODULE) — и уже из него вызываете ALTER SESSION SET NLS_LENGTH_SEMANTICS=…

Datapump это в принципе не нужно, тк он экспортирует описание вместе с nls_length_semantics столбцов источника и соответственно вставляет его при создании. Это вызывало определённые проблемы при экспорте столбцов, которые были определены с BYTE с однобайтовых баз в уникодные(те строки при конвертации из однобайтовых в уникод становились длиннее) и тогда используют стандартное решение с импортом в два этапа: сначала metadata only, затем alter нужных столбцов и затем уже импорт данных

Добрый день, полезно будет напомнить стр. 683 книги Дядюшки Тома (Oracle для профессионалов. 2016 год).
Таблица 12. 1. Четыре базовых строковых типа.
При использовании многобайтного набора символов вроде UTF8 в определениях
VARCHAR2 / CHAR я советую применять модификатор CHAR, т.е. записывать
VARCНAR2( 8 0 СНАR ), а не VARCНAR2 ( 8 0 ), т. к. ваше намерение, скорее всего, заключается
в определении столбца, который фактически может хранить 80 символов данных.
С помощью параметра NLS_LENGTH_SEМANTICS на уровне сеанса или системы
можно изменить стандартное поведение с ВУТЕ на СНАR. Я не рекомендую изменять
эту настройку на уровне системы; лучше ее использовать как часть команд ALTER
SESSION в сценариях установки схемы базы данных. Любое приложение, которое
требует от базы данных наличие специфического набора установок NLS, является
недружественным .
В большинстве случаев такие приложения не могут быть установлены
в базе данных с другими приложениями, которые не требуют таких настроек,
а полагаются на стандартные значения.
Важно также помнить о том, что верхний предел количества байтов, хранящихся
в VARCHAR2, составляет 4000. Однако даже если указать VARCHAR2 ( 4000 СНАR ), то
уместить 4000 символов в это поле может не получиться. На самом деле, может оказаться, что в это поле помещаются только 1 000 символов, если все они требуют по 4
байта для представления в выбранном наборе символов!
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации