EF Code Firstは、すべての文字列にnvarchar(max)を使用します。これによりクエリのパフォーマンスが低下しますか?


29

Entity Framework Code Firstを使用していくつかのデータベースを作成しています。アプリは正常に動作しており、一般的にCode Firstでできることにはかなり満足しています。私は必然的にプログラマーであり、DBAは2番目です。私はデータベースで何をしたいのかをC#でさらに説明するためにDataAttributesについて読んでいます。私の質問は、これらのnvarchar(max)文字列をテーブルに入れることでどのようなペナルティを食べるのかということです(下の例を参照)。

この特定のテーブルにはいくつかの列があります。C#では、次のように定義されています。

    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }
    public string Name { get; set; }
    public string Message { get; set; }
    public string Source { get; set; }
    public DateTime Generated { get; set; }
    public DateTime Written { get; set; }

Name、Source、Generated、Writtenに基づいてクエリやソートを行う予定です。NameとSourceの長さは0〜50文字、場合によっては最大150になると予想しています。このテーブルはかなり小さい(<100k行)から始まりますが、時間の経過とともに大幅に増加する(> 1m行)明らかに、メッセージは小さくても大きくてもかまいませんし、おそらく問い合わせることはないでしょう。

私が知りたいことは、名前とソースの列がnvarchar(max)150文字を超えることは決してないと予想されるときに定義されているパフォーマンスのヒットがありますか?


5
[MaxLength]または[StringLength]属性を適用する必要があるようです。広すぎるの列のいくつかの追加の可能な負の要因はここに@ PaulWhiteの答えに記載されている
マーティン・スミス

3
はいvarchar(max)どこでも使用するとパフォーマンスが低下します -しないでください!適切なデータ型を使用してください- 本当に 8000文字以上必要な場合にvarchar(max) のみ使用してください!(人の名前や電子メールがこんなに長いのを見たことはありません!)- VARCHAR(n)を使用するポイントは何ですか?詳細については
-marc_s

@marc_s素晴らしいリンク。パフォーマンスを損なうことは知っています。SQLで独自のテーブルを定義するときは、varchar(n)を使用します。私の質問は、それがパフォーマンスをどれだけ損なうかということでした(投稿されたように、それは明確に明確ではありませんでしたが)。
ネイト

回答:


24

より大きなnvarchar(max)データアイテム(8000バイト以上)はテキストストレージにあふれ、追加のI / Oが必要になります。小さいアイテムは行に格納されます。この動作を制御するオプションがあります-詳細については、MSDNの記事を参照してください。

インラインに格納されている場合、I / Oパフォーマンスの大きなオーバーヘッドはありません。データ型の処理で追加のCPUオーバーヘッドが発生する可能性がありますが、これは軽微です。

ただし、nvarchar(max)列が不要なデータベースの周囲に配置するのは、かなり貧弱な形式です。これは、いくつか持っているパフォーマンスのオーバーヘッドが広いVARCHAR列50または100文字、例えば可能性の高い1(例えば)の説明またはフリーテキストフィールドになることです、10- -そして多くの場合、データサイズがデータテーブルを理解する上で非常に有用です20文字はコードである可能性があります。このような仮定を通じて、データベースから多くの場合に推論する必要のある意味を驚くでしょう。

サポートが不十分な、または文書化されたレガシーシステムではない場合と同様に、データウェアハウジングでの作業は、理解しやすいデータベーススキーマを持つことは非常に有益です。データベースをアプリケーションのレガシーと考えている場合は、データベースを継承しようとしている人々に優しくしてください。


18

これはあなたの特定の質問に答えるものではありませんが、そもそも質問をする必要がなくなるかもしれません:C#モデルクラスの文字列変数に長さを設定することは可能です。ではなく、固定長のnvarchar型(などnvarchar(50))を使用しnvarchar(max)ます。

たとえば、次の代わりに:

public string Name { get; set; }

次を使用できます。

[StringLength(50)]
public string Name { get; set; }

必要に応じて、次のようにタイプをのvarchar代わりに強制することもできnvarcharます。

[Column(TypeName = "VARCHAR")]
[StringLength(50)]
public string Name { get; set; }

ソース:https : //stackoverflow.com/questions/7341783/entity-framework-data-annotations-set-stringlength-varchar/7341920


2
EF Coreがタイプと長さの設定を同時にサポートしていることを理解するには、この答えを見つけるvarchar(50)必要がありました()が、EF 6にはこの答えの内容が必要です。
シンジャイ

9

最大の懸念事項の索引付け。BOLから:

ラージ・オブジェクト(LOB)データ型である列はntexttextvarchar(max)nvarchar(max)varbinary(max)xml、またはimageインデックスのキー列として指定することができません。

適切にインデックスを作成できない場合、クエリが遅くなります。また、データの整合性の観点から、nvarchar(max)制限を指定するよりも多くの不正なデータをフィールドに入れることができます。


9

はい、マッピングのデフォルトのEFの行動stringにはnvarchar(max)良くありません。EF 6では、独自のカスタムコンベンションを追加して、この動作を独自のデフォルトマッピングでオーバーライドできます。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<string>()
        .Configure(s => s.HasMaxLength(200).HasColumnType("varchar") );

    base.OnModelCreating(modelBuilder);
}

OnModelCreating上記のようにオーバーライドすると、すべての文字列のデフォルトのマッピングがに変更されますvarchar(200)


1
これは、1.0 EFコアでは動作しません
ShittuジョセフOlugbengaに

the default EF behavior in mapping string to nvarchar(max) is not goodこれはあなたの一般的な意見のようです。なぜこれが良くないのか説明できますか?または、EFは、複数の言語で作業する必要があるビジネスアプリケーションのフレームワークではないと思いますか?これは、データベース上の複数の言語を処理するための望ましい列タイプだからです。
マティアスバーガー

1
@MatthiasBurger nvarchar(max)は、特にレプリケートされた環境でのパフォーマンスにとって恐ろしいです。これは一般的な意見ではなく、よく知られた事実です。
user2966445

@ user2966445すみません、誤解があったと思います:)確かに、max恐ろしいです。しかし、複数の言語(およびそれらの異なる文字セット)を処理する場合、使用する必要がありnvarcharますか?
マティアスバーガー

@MatthiasBurger確かに、異なる文字セットにはnvarcharを使用しますが、この投稿全体は、nvarcharとvarcharの使用ではなく、パフォーマンスとフィールド長に関するものです。
user2966445
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.