goo blog サービス終了のお知らせ 

へたれエンジニア日記(旧跡地)

こちらへ引っ越しました。http://d.hatena.ne.jp/toritori0318/

Oracle小話その9 CHARとVARCHAR2の違い

2006-09-25 00:47:57 | ORACLE・MSDE・Postgres
なんですかねぇ、この基本的な標題。
というのも、GOLDホルダーであるこのワタクシ…


なんと

間違って覚えておりました!
Σ( ̄□ ̄)ガーン





VARCHAR2に全部空白(半角スペース)のデータを
追加できないなんて、
間違った認識を植え付けたのは誰だー!
(K泉さんかT須さんがあやしい)




よくよく考えたらそんなわけないもん。
何でこんな風に覚えてたんだろう…






そんなわけなので、
おさらいしてみましょう。




基本的な概念としては

 CHAR   → 固定長
 VARCHAR2 → 可変長

ですね。
ここまではよいですね。
CHARは不足バイト分を半角スペースで埋めます。
VARCHAR2はもちろんそんなことせずに、入力したデータがそのまま格納されます。




以下を例にとって見てみましょう。


SQL> create table toritori(col1 char(5), col2 varchar2(5));

表が作成されました。

SQL> desc toritori
 名前                NULL?    型
 ------------------- -------- -----------------
 COL1                         CHAR(5)
 COL2                         VARCHAR2(5)

SQL> insert into toritori values('TR1', 'TR2');

1行が作成されました。

SQL> select '('||col1||')' col1 , '('||col2||')' col2 from toritori;

COL1    COL2
------- -------
(TR1  ) (TR2)







COL1はCHAR型なので、勝手にスペースが埋まっていますね



それでは、今度はVARCHAR2にもスペースを付加してみます
(これすらできないと思い込んでいた…アホか)

SQL> update toritori set col2='TR2  ';

1行が更新されました。

SQL> select '('||col1||')' col1 , '('||col2||')' col2 from toritori;

COL1    COL2
------- -------
(TR1  ) (TR2  )



結果はこうなります。
スペースを付加したら、そのデータが入力されました(当たり前)。





格納されるデータについてはこんなところですね。
それでは次に、これらのデータを検索する時の注意点です。


まず、以下の2つのセマンティクスがあることを覚えましょう。

 ①非空白埋め比較セマンティクス
  比較する文字列のどちらかが(もしくはどちらも)VARCHAR2の場合

 ②空白埋め比較セマンティクス
  比較する文字列のどちらもCHAR(またはリテラル)の場合

①の場合、半角スペースは見た目そのままの扱いで検索されます。
②の場合、半角スペースは無視されたように検索されます。




以上を踏まえて、
例を見てみましょう。(先程のデータを使うことにします)

SQL> select '('||col1||')' col1 , '('||col2||')' col2 from toritori;

COL1    COL2
------- -------
(TR1  ) (TR2  )







まずは、①の場合。(VARCHAR2の比較)

SQL> select '('||col1||')' col1 , '('||col2||')' col2 from toritori
  2  where col2='TR2';

レコードが選択されませんでした。

SQL> select '('||col1||')' col1 , '('||col2||')' col2 from toritori
  2  where col2='TR2  ';

COL1    COL2
------- -------
(TR1  ) (TR2  )




上記の結果を見てわかる通り、半角スペースが認識されて検索しています。




次に、②の場合。(CHARの比較)

SQL> select '('||col1||')' col1 , '('||col2||')' col2 from toritori
  2  where col1='TR1';

COL1    COL2
------- -------
(TR1  ) (TR2  )

↑これがHITしてしまう!



SQL> select '('||col1||')' col1 , '('||col2||')' col2 from toritori
  2  where col1='TR1  ';

COL1    COL2
------- -------
(TR1  ) (TR2  )




はい。どちらもHITしています。
半角スペースが無視されていることがわかりますね。
(こうしてみると、CHARに入っている半角スペースって
 空気みたいなものだな~)





比較セマンティクスについては
こちらのサイトで詳しく説明されています↓
http://biz.rivus.jp/string_comparison_semantics.html

 *ちなみに、上記サイトで
 「'1' = '1     ' は成立するか?」
 という検証を行なっています。
 実際行なってみると、以下の結果となりました。
  ①SELECT '式は真です' x FROM DUAL WHERE '1' = '1     ' ; ○
  ②SELECT '式は真です' x FROM DUAL WHERE 1 = '1     ' ; ○
  ③SELECT '式は真です' x FROM DUAL WHERE 1 = '     1' ; ○
  ④SELECT '式は真です' x FROM DUAL WHERE '1' = '     1' ; ×

 ④の比較は無かったので、自分で検証してみました。
 (結果は×)






そして次に、データ量・パフォーマンスについて

データ量については
ORACLEMASTERの黒本を参照すると
「VARCHAR2→容量を節約できる」
と書いてあるのですが、
ネットで彷徨ったところ、いろんな意見が飛び交っておりまして
結局どの説が本当なのかわからずじまいですw
こちらなど参照↓
http://www.geocities.jp/kimura804/rdb/InterBase/ip_ib_strings_j.htm


まあ、スペース分節約できてるんだから
黒本が正しいのでしょう。
うん、そう考えよう(適当)


パフォーマンスですが、
これもネットで調べたところ
「CHARの方がパフォーマンスがよい」
という意見が多かったです。

なのでこれ採用(適当)。
たしかに、固定長の方が早そうだし。




そして最後に、
結局どちらを使うべきか?(というか使い分ける場合があるか)


そうですね、VARCHAR2を使っておきましよう。
こっちの方が推奨されているみたいですし。
本当に固定長のデータしか入らないのであれば
CHARでもいいと思いますけどね。
でもそんなにナーバスになる必要は
ないのではないかと。





とりあえず今回はこんな所です。
CHARとVARCHAR2の違いはわかりましたか?

みなさんも間違った知識をひけらかさないように
気をつけましょう!
(俺やっちゅーの)


最新の画像もっと見る