Комментарии 21
с Oracle каждый раз нас ждут какие-то сюрпризы. Проницательный читатель сразу заметит, что "руки у нас кривые" и мы "попросту не умеем его готовить"
Отнюдь. Старый тяжелый legacy движок, абсолютно недружественный к пользователю, рассчитанный на постоянное присутствие DBA в системе.
Но там было дело в кириллице.
Varchar2 по историческим причинам предназначен для хранения строк в какой-либо однобайтной кодировке, возможность хранить их в utf-8, скорее, fallback. Для строк в чем угодно используйте nvarchar. Если, конечно, не подменили кодировку хранения nvarchar не на Unicode при создании базы ;)
То, о чем Вы пишите — 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, например, невозможно проимпортировать дамп
Ой ли?!
все равно необходима перезагрузка экземпляра чтобы импорт заработал
Да ну?!
Если все так:
1. Исходный разработчик молодец, но ему стоило написать тест об этом.
2. Разработчик выполнявший рефакторинг решил исправить то, в чем, видимо, сам не особо разбирался
А по итогу во всем обвинили Oracle :-)
Вопрос не в том, что кто-то добавил или убрал char в синтаксис statement'ом. Вопрос в том, что это котрлогичное поведение которое ты не ожидаешь от базы (не буду про стоимость и пр.) и все это нужно «всего лишь» для совместимости, которая, возможна нужна не многим.
Это нечто такое простое и базовое, что я уверен знают далеко не все.
По поводу toolзы — скрипты были сгенерированы стандартным ПО (не самописным). Там видать эти «сюрпризы» знали :). Далее система развивалась, что-то изменялось-добавлялось (скрипты писались вручную). В части есть char, в части нет :) Потом провели расследование какого фига оно таки иногда падает. Нашли, вычистили. Решили поделиться опытом. Вдруг не мы одни такие. Мало ли…
все это нужно «всего лишь» для совместимости, которая, возможна нужна не многим.
Большое количество очень крупных клиентов с очень давних времен на Oracle с крайне важными данными, поэтому вопросы надежности и совместимости это наиболее важные вопросы. По этой причине очень-очень многие обновляются на новые версии очень неохотно и только после того как новые версии становятся достаточно стабильными. Даже платят огромные суммы за Extended support. Процесс накатки скриптов для Oracle тоже уже давным давно в серьезных системах отлажен и включает все необходимые настройки и параметры. Посмотрите, например, на огромные документы от SAP.
ALTER SESSION SET NLS_LENGTH_SEMANTICS="CHAR";
Oracle очень и очень гибок, у него огромное количество разнообразных параметров и настроек на всех уровнях всех подсистем, намного больше чем у MS SQL Server, DB2, Postgres и MySQL вместе взятых, что позволяет его подстроить так как необходимо конкретной системе. Естественно, что это требует хорошего знания как самого Oracle так и смежных систем. Это же не какой-нибудь SQLite. Не хотите ничего "помнить" — пользуйтесь excel или csv файликами.
Datapump это в принципе не нужно, тк он экспортирует описание вместе с nls_length_semantics столбцов источника и соответственно вставляет его при создании. Это вызывало определённые проблемы при экспорте столбцов, которые были определены с BYTE с однобайтовых баз в уникодные(те строки при конвертации из однобайтовых в уникод становились длиннее) и тогда используют стандартное решение с импортом в два этапа: сначала metadata only, затем alter нужных столбцов и затем уже импорт данных
Таблица 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
байта для представления в выбранном наборе символов!
varchar2 и Unicode для тех, кто ничего не понимает в базах данных Oracle или ORA-12899: value too large for column