web-dev-qa-db-ja.com

NULLを許可してはいけないのはなぜですか?

データベース設計に関するこの1つの記事を読んだことを覚えています。また、NOT NULLのフィールドプロパティが必要だと言っていたことも覚えています。しかし、なぜそうなったのか覚えていません。

私が考えているように思えるのは、アプリケーション開発者として、NULLをテストする必要がないということですand存在しない可能性のあるデータ値(たとえば、文字列の空の文字列)。

しかし、日付、日時、および時刻(SQL Server 2008)の場合はどうしますか?過去の日付またはボトムアウトされた日付を使用する必要があります。

これについて何かアイデアはありますか?

127
Thomas Stringer

この表現は、NULLが不適切であると既に判断していることを示しているため、不適切な表現であると思います。たぶん、あなたは「NULLを許すべきか?」

とにかく、これが私の見解です。NULLは良いことだと思います。 「NULLが悪い」または「NULLが難しい」という理由だけでNULLを防止し始めると、データの作成が始まります。たとえば、私の生年月日がわからない場合はどうなりますか?あなたが知るまで、あなたは何をコラムに入れますか?多くの反NULL関係者のような場合は、1900-01-01と入力します。今、私は老人病棟に配置され、おそらく地元のニュースステーションから、長寿を祝福し、長生きするための秘密を尋ねるなどの電話を受けます。

わからない列の値である可能性がある場所に行を入力できる場合、私はNULLだと思いますそれが未知であるという事実を表すために任意のトークン値を選択するよりもはるかに理にかなっています-他の人がすでに知っている必要がある値、リバースエンジニアリング、またはそれが何を意味するかを理解するために尋ねるでしょう。

ただし、バランスがあります。データモデルのすべての列がnull可能である必要はありません。多くの場合、フォームにはオプションのフィールドがあり、そうでなければ行が作成されたときに収集されない情報があります。しかし、それは、データのallの移入を延期できることを意味しません。 :-)

また、NULLを使用する機能は、実際の重要な要件によって制限される場合があります。たとえば、医療分野では、値が不明である理由を知ることは、生死の問題になる可能性があります。脈拍がなかったため、またはまだ測定していないため、心拍数はNULLですか?そのような場合、心拍数列にNULLを入れて、理由があるためにノートまたは別の列にNULLを含めることができますか?

NULLを恐れないでください。ただし、いつ、どこで、いつ、どこで使うべきではないかを学び、指示してください。

232
Aaron Bertrand

確立された理由は次のとおりです。

  • NULLは値ではないため、固有のデータ型はありません。実際の型に依存するコードが型指定されていないNULLを受け取る可能性がある場合、ヌルは場所全体の特別な処理を必要とします。

  • NULLは2値(おなじみのTrueまたはFalse)ロジックを破壊し、3値ロジックが必要です。これは正しく実装することさえもはるかに複雑であり、ほとんどのDBAやほとんどすべての非DBAによって確かによく理解されていません。結果として、アプリケーションで積極的に多くの微妙なバグを招きますです。

  • 実際の値とは異なり、特定のNULLのセマンティックな意味はアプリケーションに任されています

    「該当なし」、「不明」、「センチネル」などのセマンティクスは一般的ですが、他にもあります。同じリレーション内であっても、同じデータベース内で同時に使用されることがよくあります。そしてもちろん不明確で区別がつかず互換性がないの意味です。

  • これらは、 「ヌルのない欠落情報を処理する方法」 で論じられているように、リレーショナルデータベースには必要ありません。さらなる正規化は、NULLのテーブルを削除することを試みる最初のステップです。

これは、NULLが許可されてはならないという意味ではありません。それはdoesは、可能な限りNULLを許可しない多くの正当な理由があると主張しています。

重要なのは、より良いスキーマ設計、より良いデータベースエンジン、さらにはより優れたデータベース言語を介して、NULLをより頻繁に回避することを実現可能にするmakeことを非常に一生懸命試みることです。

Fabian Pascalは、 “ Nulls Nullified” のように、多くの引数に応答します。

61
bignose

Nullはデータベース設計の重要な要素です。代替案は、あなたもおっしゃったように、欠落または不明を表す既知の値の急増です。問題は、nullが広く誤解され、結果として不適切に使用されていることにあります。

IIRC、コッドは、nullの現在の実装(存在しない/欠落を意味する)は、1つではなく2つのnullマーカー、「存在しないが適用可能」と「存在せず適用不可」を使用することで改善できることを示唆しました。個人的にこれによってリレーショナルデザインがどのように改善されるかは想像できません。

32

まず、私はDBAではありません。私は開発者であり、私たちのニーズに基づいてデータベースを保守および更新しています。そうは言っても、いくつかの理由で同じ質問がありました。

  1. Null値は開発をより困難にし、バグを起こしやすくします。
  2. Null値は、クエリ、ストアドプロシージャ、およびビューをより複雑にし、バグを起こしやすくします。
  3. ヌル値はスペースを使用します(固定列長に基づく?バイト、または可変列長の2バイト)。
  4. Null値は、インデックス付けと数学に影響を与える可能性があり、影響を与えることがよくあります。

私はインターネット全体で大量の応答、コメント、記事、アドバイスをふるいにかけるのに非常に長い時間を費やしています。言うまでもなく、ほとんどの情報は@AaronBertrandの応答とほぼ同じでした。そのため、この質問に答える必要があると感じました。

まず、将来のすべての読者のために何かをまっすぐに設定したいと思います... NULL値は、未使用のデータではなく未知のデータを表します。終了日フィールドを持つ従業員テーブルがある場合。終了日のnull値は、現在不明な将来の必須フィールドであるためです。アクティブまたは退職したすべての従業員は、いつかそのフィールドに日付が追加されます。それが私の意見では、ヌル可能フィールドの唯一の理由です。

とは言っても、同じ従業員テーブルが何らかの認証データを保持している可能性が高いです。企業環境では、従業員は人事および経理のデータベースにリストされますが、認証の詳細を常に持っている必要はありません。ほとんどの応答は、これらのフィールドをnullにすること、または場合によってはそれらのアカウントを作成しても、資格情報を送信しないことは問題ないと考えます。前者は、開発チームにNULLをチェックしてそれに応じて処理するコードを記述させ、後者は大きなセキュリティリスクを引き起こします。システムでまだ使用されていないアカウントは、ハッカーがアクセスできる可能性のあるアクセスポイントの数を増やすだけでなく、使用されないもののために貴重なデータベーススペースを占有します。

上記の情報を踏まえると、使用されるNULL可能データを処理する最良の方法は、NULL可能値を許可することです。それは悲しいですが本当であり、あなたの開発者はそれを嫌います。 2番目のタイプのnull許容データは、関連テーブル(IE:アカウント、資格情報など)に配置し、1対1の関係にある必要があります。これにより、必要な場合を除き、ユーザーは資格情報なしで存在できます。これにより、余分なセキュリティリスクと貴重なデータベーススペースが削除され、よりクリーンなデータベースが提供されます。

以下は、必要なnull許容列と1対1の関係の両方を示す非常に単純なテーブル構造です。

Unknown Nullable and One-to-One relationship

私はこの質問が何年も前に尋ねられてからパーティーに少し遅れていることを知っていますが、うまくいけば、これがこの問題とそれに対処する最善の方法にいくつかの光を当てるのに役立つでしょう。

14

NULLを混乱させる開発者のすべての問題とは別に、NULLには別の非常に重大な欠点があります。パフォーマンス

NULL可能列は、パフォーマンスの観点からは災いです。例として整数演算を考えてみましょう。 NULLのない健全な世界では、SIMD命令を使用してデータベースエンジンコードで整数演算をベクトル化して、CPUサイクルあたり1行よりも速い速度でほとんどすべての計算を実行するのは「簡単」です。ただし、NULLを導入した瞬間、NULLが作成するすべての特殊なケースを処理する必要があります。最近のCPU命令セット(読み取り:x86/x64/ARMおよびGPUロジックも)は、これを効率的に実行する機能を備えていません。

例として除算を考えます。非常に高いレベルでは、これはnull以外の整数で必要なロジックです。

if (b == 0)
  do something when dividing by error
else
  return a / b

NULLでは、これはもう少しトリッキーになります。 bと一緒にbがnullの場合、aの場合も同様にインジケーターが必要になります。チェックは次のようになります。

if (b_null_bit == NULL)
   return NULL
else if (b == 0) 
   do something when dividing by error
else if (a_null_bit == NULL)
   return NULL
else 
   return a / b

NULL演算は、最新のCPUでの実行に、nullでない演算よりもかなり低速です(約2〜3倍)。

SIMDを導入するとさらに悪化します。 SIMDを使用すると、最新のIntel CPUは、次のように1つの命令で4 x 32ビット整数除算を実行できます。

x_vector = a_vector / b_vector
if (fetestexception(FE_DIVBYZERO))
   do something when dividing by zero
return x_vector;

現在、SIMDランドでNULLを処理する方法もありますが、これには、より多くのベクトルとCPUレジスタを使用し、巧妙なビットマスキングを行う必要があります。優れたトリックを使用しても、比較的単純な式でさえ、NULL整数演算のパフォーマンスペナルティが5〜10倍遅い範囲に忍び込みます。

上記のようなものは、集約についても、ある程度は結合についても当てはまります。

言い換えると、SQLにおけるNULLの存在は、データベース理論と現代のコンピュータの実際の設計との間のインピーダンスの不一致です。 NULLが開発者を混乱させるかなりの正当な理由があります-ほとんどの正気なプログラミング言語では整数をNULLにすることはできないためです-それはコンピューターがどのように機能するかではありません。

13
Thomas Kejser

SQL Nullに関するWikipediaの記事 は、NULL値についていくつかの興味深いコメントがあります。データベースに依存しない回答として、特定のRDBMSにNULL値を持つことの潜在的な影響を知っている限り、あなたのデザインで許容できます。そうでない場合は、列をnull可能として指定できません。

RDBMSが数学などのSELECT操作やインデックスでそれらをどのように処理するかに注意してください。

10
Derek Downey

興味深い質問。

アプリケーション開発者としては、NULLや存在しない可能性のあるデータ値(たとえば、文字列の場合は空の文字列)をテストする必要がないということしか考えられないようです。

それよりももっと複雑です。 nullにはいくつかの明確な意味があり、多くの列でnullを許可しない重要な理由の1つは、列がnullの場合、これは1つだけのことを意味します(つまり、外部結合に表示されなかった)。さらに、それはあなたが本当に役立つデータ入力の最低基準を設定することを可能にします。

しかし、日付、日付時刻、および時刻(SQL Server 2008)の場合はどうしますか?過去の日付またはボトムアウトされた日付を使用する必要があります。

つまり、nullの問題がすぐにわかります。つまり、テーブルに格納された値は、「この値は適用されない」または「わからない」のいずれかを意味します。文字列では、空の文字列は「これは適用されません」として機能しますが、日付と時刻では、従来これを意味する有効な値がないため、そのような規則はありません。通常、ここではNULLを使用してスタックします。

これを回避する方法は(リレーションを追加して結合することにより)ありますが、これらはデータベースにNULLがある場合とまったく同じ意味上の明確さの問題を引き起こします。これらのデータベースについては、これについて心配する必要はありません。本当にできることは何もありません。

編集:NULL areが必須である1つの領域は、外部キーにあります。ここで、それらは通常、1つの意味しか持たず、外部結合のnullと同じです。これはもちろん問題の例外です。

10
Chris Travers