- PR -

CHARに対するVARCHARの欠点

投稿者投稿内容
みやも
ベテラン
会議室デビュー日: 2002/04/22
投稿数: 74
投稿日時: 2003-07-11 13:54
お世話になります。

DBフィールドのCHARの箇所をVARCHAR2に変更しようと思っています。この場合に注意しないといけない点があったら教えていただけないでしょうか?(CHARをVARCHARにすると遅くなる?とか)。

環境はJDK1.4.1 + Oracle JDBC Driver 9.2.0で、DBはOracle9iです。
DBは設計中なので変更が可能です。

[補足]
変更したい理由は以下です。
DB上のCHAR型のフィールドについて"PreparedStatement"で操作しようとしたとき、以下の問題(正しい動作だが不便な気がする動作)があります。

・比較文字(WHERE句)に指定するデータにちゃんと空白を指定しないと、一致しない。
 (例えば、DB上のデータが"001 "だった場合、検索条件は"001"ではマッチせず、"001 "じゃないとマッチしない)

・検索時にResultSetから取得したデータが空白パディングされる
 (入っているデータが空白付だから正しくはあるんですけど。INSERT時は自動で挿入されるのに、取得字はtrimしないのも?)

で、イチイチ空白操作するのも大変なので、CHARをVARCHARにしようと思いました。なお、上記問題はDBMSによって、Statementの種類によって異なります。


[ メッセージ編集済み 編集者: みやも 編集日時 2003-07-11 13:56 ]
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2003-07-11 15:23
こんにちは。

注意点をひとつ。

ご存知だと思いますが、CHARは固定長、VARCHAR2は可変長文字列です。
他のDBでも同じでしょうが、Oracleではデータブロックに行データがぎゅうぎゅうづめ
に入っています。
簡単に言えば、固定長であれば行サイズも変化は無いため行データに更新があっても
影響ありませんが、可変長であれば更新後に行データが更新前より大きくて、データ
ブロックに入りきらなければあふれた分を別ブロックに移動したりして、行連鎖という
現象が起こりやすくなります。
行連鎖が多いと、多少パフォーマンスに影響があります。
詳しくはOracle関連のサイトで調べてみてください。

しかし、CHAR型とVARCHAR型はそれぞれ一長一短で、データの性質や大きさ、更新頻度
などによって使い分けるものです。

空白操作が大変だからというのはプログラマーの都合でのデータベース設計ではない
でしょうか?
プログラマーの都合でのデータベース設計したもので、トラブルを抱えているのを
よく見かけます。
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2003-07-11 16:38
maruさんの書き込み (2003-07-11 15:23) より:
>簡単に言えば、固定長であれば行サイズも変化は無いため行データに更新があっても
影響ありませんが、可変長であれば更新後に行データが更新前より大きくて、データ
ブロックに入りきらなければあふれた分を別ブロックに移動したりして、行連鎖という
現象が起こりやすくなります。

固定長でもNULL可なら可変長と同じですね。
なので、更新頻度の多いカラムだと固定長NULL不可という設計をする場合がよくあります。
ino
常連さん
会議室デビュー日: 2003/04/17
投稿数: 25
お住まい・勤務地: 大阪
投稿日時: 2003-07-11 16:55
引用:

みやもさんの書き込み (2003-07-11 13:54) より:
・検索時にResultSetから取得したデータが空白パディングされる



既にデータの入ってるCHARのカラムをVARCHAR2に変えても
パディング済みの空白は残りますんで、カラムの型を
変えた後に、空白をトリミングしておかないと
「検索条件="001"」では、ヒットしません。

#当たり前?
#でも私は先日、うっかりトリミングを忘れてエラい目にあいました
みやも
ベテラン
会議室デビュー日: 2002/04/22
投稿数: 74
投稿日時: 2003-07-11 21:49
アドバイスありがとうございます。
行連鎖、NOT NULL、トリミングのお話、とても参考になりました。

ただ、どちらが適当か、について悩む場面があります。
例えば、以下の場合CHARとVARCHAR2のどちらが適切でしょうか?

・ユーザーID
 例:hoge1, foobar2
 主キーである

・部門コード
 現在8桁固定なのだが、将来的に桁が増えるかもしれないので
 9桁取ることになっている

・製品コード
 基本的に10桁だが、たまに12桁のものもある。

上記のような例でパフォーマンスに影響がなければ(←ある?)、VARCHAR2でいいのでは?と思っているのですが、それは間違いでしょうか?


>空白操作が大変だからというのはプログラマーの都合でのデータベース設計ではない
でしょうか?

すみません。かなりプログラマーの都合になってます。でも、プログラマがミスしにくいようには設計した方がよいですよね。


[ メッセージ編集済み 編集者: みやも 編集日時 2003-07-11 21:50 ]
まりり
ぬし
会議室デビュー日: 2001/12/05
投稿数: 329
投稿日時: 2003-07-11 23:53
> 上記のような例でパフォーマンスに影響がなければ(←ある?)、VARCHAR2でいいので > は?と思っているのですが、それは間違いでしょうか?

どの程度を気にしていますか?
Webアプリであればネットワークのほうがはるかにボトルネックになりえるんじゃ
ないかと思いますが。


あと、

> すみません。かなりプログラマーの都合になってます。でも、プログラマが
> ミスしにくいようには設計した方がよいですよね。

これがDB変更したい理由であればラッパークラスを作るほうが早いんじゃ
って思います。やることははっきりしてますよね。

Javaに限らず、ルーチンを共通化するのって真っ先にやっておくべきです。
そのほうがDBアクセスにパフォーマンスが出ないときなんかにモニタしやすかったり、
メリットもありそうな気がします。
raystar
ぬし
会議室デビュー日: 2003/01/16
投稿数: 251
お住まい・勤務地: Tokyo/Japan
投稿日時: 2003-07-12 14:56
CHAR だと結合時にTRIMしないといけないんですよね。
そうするとINDEXがはれませんのでFULLスキャンかかることに
なると思います。
関数INDEXって手もありますけど、、、

VARCHAR2をお勧めします。
たいしたネックにはならないはずです。
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2003-07-12 15:56
raystarさんの書き込み (2003-07-12 14:56) より:
>CHAR だと結合時にTRIMしないといけないんですよね。

同じ長さのCHARどうしならそういうことはありませんね。
普通結合の対象となるカラムは同一の型で設計しますよね。

>VARCHAR2をお勧めします。

通常はそうですね。データの長さがまちまちで変更がほとんどないようなカラムなら、
VARCHARのほうが適当でしょう。

スキルアップ/キャリアアップ(JOB@IT)