【Oracle設計】NULLを許容する列とNOT NULL制約の明確化

オプティマイザ統計情報/実行計画

~“なんとなくNULL可”が招くバグと性能劣化を未然に防ぐ~


■ はじめに

Oracleのテーブル設計において、「この列はNULLを許容するのか?しないのか?」という判断は、データ品質・アプリの堅牢性・SQLパフォーマンスに直結する極めて重要なテーマです。

ところが現場では、

  • 「とりあえず全部NULL可にしておこう」
  • 「NOT NULLをつけなくても、まあ大丈夫だろう」
  • 「アプリでチェックしてるから不要」

といった曖昧な設計がよく見受けられます。

このような設計は、後々の不具合・性能劣化・保守コストの増加を招きます。

💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?

Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?


■ NULLとは何か?NOT NULL制約とは?

まず基本を整理しましょう。

┌────────────┬──────────────────────────────┐
│ 種類 │ 説明 │
├────────────┼──────────────────────────────┤
│ NULL許容列 │ 値が未入力でも登録可。空の状態が許される。 │
│ NOT NULL制約あり列 │ 必ず値が必要。NULLは許されず、INSERTで値必須。 │
└────────────┴──────────────────────────────┘

✅ Oracleでは、制約を明示しない場合、列はNULLを許容します。


■ NULLを安易に許容するとどうなるか?

・本来必要なデータが空欄のまま登録される  
・アプリ側のIF分岐やnullチェックが増える
・インデックスが効かない
・JOINや集計時に意図しない結果になる
・「本当に空なのか、未入力なのか」が不明になる

📘 テキスト図:NULLを許容した結果起きた問題

┌────────────┬────────────────────────────┐
│ カラム名 │ 問題の例 │
├────────────┼────────────────────────────┤
│ 社員番号 │ NULLでJOIN失敗 → 勤怠情報が集計対象外に │
│ 登録日 │ NULLで並び順が想定とズレる │
│ メールアドレス │ NULLにより通知失敗、エラー未検知 │
│ 顧客区分 │ NULLでWHERE句にヒットせず → 誤課金が発生 │
└────────────┴────────────────────────────┘

■ NOT NULLにすべき典型的な列

カラム例NOT NULLを推奨する理由
主キー(例:user_id)NULL不可。識別子として常に値が必要。
氏名・商品名空では業務が成り立たない。
作成日時監査・ログ管理上、必ず必要な情報。
ステータス区分NULLだと処理分岐の条件に引っかからないリスクがある。

📘 テキスト図:設計時のNULL可否判断

┌──────────────┬────────────┬────────────────────────┐
│ カラム名 │ NULL可否 │ 判断理由 │
├──────────────┼────────────┼────────────────────────┤
│ member_id │ NOT NULL │ 主キー。NULLは一意性を保てない。 │
│ member_name │ NOT NULL │ ユーザー表示に必要不可欠。 │
│ email │ NULL可 │ 任意入力項目。登録時に未入力あり得る。 │
│ resign_date │ NULL可 │ 現役社員は退職日が未定のためNULLが適切。 │
│ remarks │ NULL可 │ 備考欄。業務上、空欄が許容される。 │
└──────────────┴────────────┴────────────────────────┘

💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?

Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?


■ Oracleにおける索引とNULLの関係

Oracleでは、Bツリー索引はNULL値を無視するため、以下のような事象が発生します。

❌ 悪い例(email列にインデックスがある)

SELECT * FROM members WHERE email IS NULL;

このクエリは索引を使わず、全表スキャンになります。


✅ 対策:関数インデックスの利用

CREATE INDEX idx_email_null
ON members(NVL(email, 'NONE'));

このようにすれば、NULL相当を’NONE’として格納することでインデックスが効きます。


■ NOT NULL制約を活用するメリット

・DBレベルでデータ品質が担保される(漏れが防げる)  
・INSERT失敗により不正データを事前にブロック
・アプリのバリデーションコードを簡素化
・インデックスが効く → SQLが高速に

📘 テキスト図:アプリ vs DBバリデーション

┌──────────────┬────────────────────┐
│ アプリでチェック │ DB(NOT NULL)でチェック │
├──────────────┼────────────────────┤
│ 実装工数が必要 │ CREATE TABLE時に定義だけで済む │
│ チェック漏れが発生しやすい │ 常にDBが厳密にバリデートする │
│ 画面別に制御が必要 │ 一元的な制約管理が可能 │
└──────────────┴────────────────────┘

■ 制約の変更方法(設計後の対応)

後から「やっぱりNULLを許容したい/許容したくない」となった場合のDDLです。

🔄 NULL → NOT NULL に変更

ALTER TABLE members MODIFY email NOT NULL;

※すでにNULL値があると失敗します。事前にUPDATEで埋める必要あり。


🔄 NOT NULL → NULL可に変更

ALTER TABLE members MODIFY email NULL;

※こちらは即時可能です。


■ 実行計画でも差が出る

-- NULLが混在すると索引が効かず FULL SCAN に
EXPLAIN PLAN FOR
SELECT * FROM members WHERE email IS NULL;

-- NOT NULL制約があれば、インデックスを活かしたクエリ設計がしやすい

■ まとめ

Oracleのテーブル設計において、NULLを許容するかどうかの判断は、単なる好みではなく「設計の意思決定」です。

✅ 設計時のチェックポイント

  • 主キー列には必ず NOT NULL をつける
  • 空が許される業務項目以外は NOT NULL を明示する
  • NULL列にはインデックス非効率のリスクがあることを認識する
  • アプリではなくDB側で制約を担保する方が堅牢


[参考]
Oracle Database データベース開発ガイド 19c

💰 【PR】Oracleエンジニアの市場価値、調べてみませんか?

Oracleのスキルは需要が高く、特定の資格や経験を持っていると年収が大幅にアップするケースがあります。まずはIT専門のエージェントで非公開求人をチェックしてみませんか?

コメント

タイトルとURLをコピーしました