私たちが開発している製品が複数のリレーショナルデータベースで動作するのは偶然です。現在、これらはMS SQL、Postgres、およびOracleです。MySQLから故人、おそらくFirebirdやDB2を備えたエキゾチックなSybaseまで、多くのことでローンチがありましたが、それは話ではありません。
MS SQLとPostgresを使用すると、すべてが明確でなじみがない場合、Oracleを使用すると、毎回いくつかの驚きがあります。賢明な読者はすぐに「私たちの手が曲がっている」ことに気づき、私たちは「それを調理する方法がわからない」ことに気付くでしょうvarchar2
。
最新のすべてのシステムと同様に、データはUnicode形式(現在はUTF-8)で保存されます。なぜこれがリレーショナルデータベースにとって重要なのですか?
たとえば、データベースにユニコードと非ユニコードのデータタイプが混在している場合、一部のドライバはこれを実行できません。たとえば、JTDS-MS SQLサーバー用のJDBCドライバーは、UnicodeモードまたはAnsiのいずれかで動作します。したがって、非ユニコード列(varchar / char)を「保存」して作成することにした場合、テーブルへのデータ挿入のレベルでユニコード-> ansi変換が行われ、おそらく逆の効果が得られます(少なくともデータ挿入の速度が低下します。および検索中)。
だから話。アプリケーションサーバーは、フィールドを挿入する前にフィールドの最大許容長をチェックします(ここでは、チェックがデータベースデータではなく、内部メタデータに従って実行されるように指定する必要があります)が、それにもかかわらず、Oracleでは次のようなエラーを「キャッチ」することがあります。ORA-12899: value too large for column.
どんな攻撃?さらに、スクリプトはすべてのデータベースでほぼ同じ方法で生成されますが、問題が発生するのはたまにしかなく、Oracleでのみ発生します。
私は苦しめません。varchar2
データが保存されているタイプの仕様を注意深く読んでいないことが判明しました:)
たとえば、列のサイズを次のように変更してみましょう。
alter table address modify street varchar2(150);
150は(他の一般的なベースのように)文字の長さは何だと思いますか?ヒント-いいえ:)おそらくバイト単位です。
そしてシンボルではそれは
alter table address modify street varchar2(150 char);
それら。仕様を指定せずにchar
-byte
デフォルトのデータベース設定の灰色の領域に自分自身を見つけます。さらに、到達可能なすべてのデータベース(本番環境だけでなく本番環境も含む)では、デフォルト設定はバイトです。
, UTF-8, , 4 ( 1 ANSI, 2 4 ).
Unicode !? , , , " ". .. , : legacy, , Unicode' " ", , backup 86 imp - .
? tool, , create table
char
:)
:
, , , .
SELECT value FROM NLSDATABASEPARAMETERS WHERE parameter='NLSLENGTHSEMANTICS';
, , " ":
SELECT TABLE_NAME, COLUMN_NAME, DATA_LENGTH, CHAR_USED
FROM USER_TAB_COLUMNS
WHERE DATA_TYPE = 'VARCHAR2' AND CHAR_USED = 'B'
ORDER BY TABLE_NAME, COLUMN_NAME
P.S. , , (, 100% ansi ), Unciode … ...
P.P.S. Regexp " " varchar2\(\s*\d+\s*\)
P.P.P.S. StackOverflow
PPPPS NLSLENGTHSEMANTICS
Oracleでは、インスタンスまたはサーバーのパラメーターファイルでNLS LENGTH SEMANTICSパラメーターをCHARに設定しないことを強くお勧めします。これにより、多くの既存のインストールスクリプトが文字長のセマンティクスを持つ列が予期せず作成され、バッファオーバーフローなどのランタイムエラーが発生しました。」https://docs.oracle.com/cd/E24693 01 / server.11203 / e24448 / initparams149.htm