trapemiyaの日記

hatenablogが新しくなったんで新規一転また2019年1月からちょこちょこ書いてます。C#中心のプログラミングに関するお話です。

SQL ServerのNプレフィックス

今から約10年ほど前に、SQL ServerのNプレフィックスについて旧MSDNフォーラムに投稿しましたが、今はアクセスできなくなっていますので、以下に載せておきます。当時の原文のままです。なお、当時の私のハンドル名はMIYAでした。
ーーーーーーーーーーーーーーーーーーーーー
MIYA

参加日: 2003-5-6
投稿数: 1641

Re: SqlServerでの日本語定数の使用
投稿日時: 2004-11-14 午後 6:07
こんにちは。MIYAです。

(以下の文について、私も100%の自信があるわけではありません。いろいろな記事、および経験から総合的に私は以下のように理解しています。誤りがあればご指摘ください。(^^;)

日本で普通にSQLserverをインストールした場合、SQLserverにおける既定のコードページはjapanese(コードページ932、以下CP932)です。これは基本的にS-JISです。
SQLserverはこのコードページを切り替えることにより、多言語に対応しています。しかし、複数の言語を扱う場合はどうでしょうか?これははっきり言って不可能です。
そこで、複数言語を統一的に扱えるunicodeの対応が、SQLserver7.0で初めて実現されました。これでSQLserverは、既定のコードページとunicodeの両方を扱えるようになりました。

そこで、じゃぁ、どっちを使うのという問題が発生します。charは非unicode、ncharはunicodeで保存するのはご存知だと思います。
SQLserverへ文字がやってきた時、それは単にビットストリームですから、それをエンコードして文字として認識しなければなりません(binary型への保存だとそのまま入ります)。
これは、ブラウザでビットストリームを文字にエンコードして表示するのに似ています。
さて、SQLserverエンコードする時に、SQLserverは規定のCP932でエンコードしようとします。大抵のやってくる文字はS-JISなので問題なくエンコードされます。charの列だとこのまま保存されますし、ncharの列だとここからunicodeに変換されて保存されます。

やってきた文字がS-JISでは無い場合はどうでしょうか?例えば「まるいん(丸付きの印)」はunicodeです。この文字をSQLserverは既定のCP932としてエンコードしようとします。しかし、もともとS-JISに無かった文字なのでunicodeを使ってSQL文を作ったぐらいですから、エンコードに失敗します。失敗すると「?」になります。charだとこの「?」が保存され、ncharだとunicodeに変換され、unicodeの「?」が保存されます。

では、「まるいん(丸付きの印)」を保存する方法は無いのでしょうか?あります。Nプレフィックスを使えば良いのです。
この場合、SQLserverは既定のコードページではなく、unicodeエンコードします。
しかし、unicodeですから当然ncharにしか保存されず、charには「?」と保存されてしまいます。
Nプレフィックスを「まるいん(丸付きの印)」のようなunicodeではない普通のS-JISに使ったらどうなるでしょうか?この場合もSQLserverはNプレフィックスが付いているので、unicodeとしてエンコードしようとします。しかしS-JISのため、既定のコードページを利用してunicodeとしてエンコードすることになります。

以上は保存時でしたが、select時も同様です。「まるいん(丸付きの印)」のようなunicodeの文字をNプレフィックス無しでSQLserverに送った場合、charだろうがncharだろうが「?」で保存されます。これをselectでNプレフィックス無しで「まるいん(丸付きの印)」で検索した場合、「?」に変換されて検索されることになり、先に保存した「?」にヒットして、検索結果として「?」が返されます。

以上よりncharなどのunicode型の列を使用する場合、どのみちビットストリームを最終的にunicodeに変換しなければならないため、unicodeの文字だけではなく、Nプレフィックスを常に付けても良いと思います。逆に付けないと一度CP932にエンコードされてからふたたびunicodeに変換されるため、非効率だと思います。
しかし、charなどの非unicode型を列に使用する場合は、ビットストリームを一度既定のコードページ経由でunicodeに変換し、それをふたたびCP932に基づいて変換する必要があり無駄が発生します。といいますか、charなどの非unicode型にはunicodeで保存できませんので、Nプレフィックスを使うこと自体が無意味です。

全く「まるいん(丸付きの印)」のようなunicode文字を使わず、CP932のみで良い場合はncharとかではなく、charなどの非unicode型を使う方が効率的です。S-JISからunicodeへの変換も発生しませんし、記憶容量も小さくなります。

unicodeというと多言語対応ということが前面に出ますが、日本語に限った場合でもunicodeの文字まで必要なのかどうかということで、charかncharの選択がわかれます。

簡単にまとめると、ncharなどのunicode型に保存する場合はNプレフィックスを常に付ける、charなどの非unicode型に保存する場合には付けない(むしろ付けると効率が悪い)。というように私は理解しておりますが、何分詳細まできっちりとわかっているわけではないので、ncharなどのunicode型に保存する場合でも、S-JISの場合にはNプレフィックスを付けないほうが効率が良いという事実があるのかもしれません。

>データアダプター構成ウィザードでデータアダプターを自動生成した場合、Nプレフィックスを使用していないようですが。

これは既定のコードページが基本になっているからだと思います。先に述べたように、charなどだと全く無意味になるどころか、かえって非効率になるからではないでしょうか?textBoxに「まるいん(丸付きの印)」などの文字を打ち込んでSQLserverに保存する可能性がある場合は、Nプレフィックスを付けて下さい。でないと「?」で保存されてしまいます。
コードページという概念をやめて全てunicodeで統一すればNプレフィックスなど気にする必要は無くなるのですが、世の中にはまだまだunicodeを扱えないものが多く存在するので、そうもいかないのでしょうね。