varcharとnvarcharのSQL Serverデータ型の主なパフォーマンスの違いは何ですか?


236

私は学校の小さなWebアプリのデータベースをで使用していSQL Server 2005ます。vs
の問題について、いくつかの考えの集まりが見られます。varcharnvarchar

  1. 使用varcharあなたが国際化されたデータの多くに対処しない限り、その後使用nvarchar
  2. nvarcharすべてに使用するだけです。

ビュー2のメリットが見え始めています。nvarcharは2倍のスペースを占めることはわかっていますが、これは数百人の学生のデータを保存するだけなので、必ずしも大したことではありません。私には、それを心配せずに、すべてにnvarcharの使用を許可するのが最も簡単なようです。それとも私が見逃しているものはありますか?


ここで同様の質問:stackoverflow.com/questions/312170/…編集:le dorfier:興味深いことに、正反対の結論に至りました。
Booji Boy

6
反対の結論に至ったはるかに広範なスレッドを参照してください。stackoverflow.com/questions/312170/...
dkretz

2
ジェイソン:これが不適切なリクエストではないことを願っていますが、受け入れられた回答をgbnに変更することを検討してください。ジョーバローネの答えは多くの理由でひどく間違っています。それが「受け入れられる」と、初心者は誤った選択をするようになります。「常に使用NVARCHAR」することは不要で無駄であり、パフォーマンスとハードウェアのコスト/予算に非常に悪影響を及ぼす可能性があります。数行でも、数千行でも問題ありません。しかし、システムは人々が期待するよりも急速に成長するので、現在受け入れられている答えはコミュニティへの害です。ありがとうございました。
ソロモンルツキー

回答:


140

常にnvarcharを使用してください。

ほとんどのアプリケーションでは、2バイト文字は必要ない場合があります。ただし、2バイト言語をサポートする必要があり、データベーススキーマで1バイトしかサポートしていない場合、アプリケーション全体に戻って変更するのは非常にコストがかかります。

1つのアプリケーションをvarcharからnvarcharに移行するコストは、ほとんどのアプリケーションで使用する少しの追加のディスク領域よりはるかに高くなります。


4
戻って多言語のテキスト/メッセージ、タイムゾーン、測定単位、通貨のサポートを追加するのははるかに難しいので、誰もが常に最初の日から常にアプリケーションでこれらをコーディングする必要があります(ホームページWeb上にある場合でも)アプリ)!
和基。

82
インデックスサイズ、メモリ使用量などはどうですか?tinyintも「念のため」使用できる場合は、常にintを使用すると思いますか?
gbn 2010

99
常に多言語サイトのコーディング/計画(必要なインクリングがない場合)は、すべての若者に最初の車に大きな8席のガスに満ちたSUVを購入するように指示するようなものです...結局のところ、彼らはいつか結婚し、6人の子供がいるかもしれません。私はパフォーマンスと効率を楽しみたいですが、アップグレードの代金を支払うことができます。
EJブレナン

4
@cbmeeks:わからないことについてはコーディングしません。しかし、目立ったパフォーマンスヒットなしで使用できる場合、データベースはそれが問題になるほど大きくありません...
gbn

60
通常、人々が「常に」という言葉で答えを始めるときは、その後のすべてを無視する必要があります。(私がその文を「通常」という言葉で始めたことに注意してください。)
ブランドンムーア

226

ディスク容量は問題ではありませんが、メモリとパフォーマンスが問題になります。ページ読み込みを2倍、インデックスサイズを2倍、奇妙なLIKEおよび=一定の動作など

中国語などのスクリプトを保存する必要がありますか?はい、もしくは、いいえ...

そしてMS BOLから「Unicodeのストレージとパフォーマンスへの影響

編集

nvarcharのパフォーマンスがいかに悪いかを強調する最近のSOの質問...

SQL Serverは、nvarchar文字列内を検索するときに高いCPUを使用します


19
1アプリケーションが国際的になった場合、あなたはその検索を心配する他の多くの問題があるでしょう/ nvarchar型に置き換える:指標と通貨の多言語テキスト/メッセージ、タイムゾーン、単位
KM。

2
しかし、ホセやビョルンのように時々外国の名前を保存する必要がある場合はどうでしょうか?
Qwertie 2012年

7
@Qwertie:nvarcharを使用します。やらないことは不必要に使う。これらの2つの名前は、とにかくIIRCのvarcharに適合します
gbn

6
ディスク容量が問題ではないと言うことは、誰にとっても真実ではありません。長年にわたって何十億ものレコードが保存されている大規模な銀行アプリケーションで、nvarcharを不必要に単純に使用してきました。レプリケーション、バックアップ、ディザスタリカバリを備えた高価なSANベースのストレージでは、これは実際にnvarcharとvarcharの数百万ドルのコストに相当します。言うまでもなく、読み取りごとにディスクから2倍のバイトを読み取る必要があるため、パフォーマンスに大きな(100%)影響があります。
codemonkey、2014

2
@codemonkeyほか:次の記事で、無駄なスペースの問題に総合的に対処するためにできることを行いました:ディスクは安いです!ORLY?(ただし、無料の登録が必要です)。この記事は、codemonkeyが高額なエンタープライズレベルのストレージに関して遭遇した状況を防ぐのに役立つことを目的としています。
ソロモンルツキー

59

一貫してください!VARCHARをNVARCHARに結合すると、パフォーマンスに大きな影響があります。


115
文字フィールドで結合を実行している場合、一般的に言えば、nvarcharを使用するかvarcharを使用するかよりもデータベースの問題がおそらく悪化します。
Brandon Moore

@ThomasハーランAの簡単なテストでは、参加の間には具体的な差がないことを私に示しているnvarcharvarchar変換対nvarcharvarcharしてまで参加しますvarchar。もちろん、結合ではなく列のデータ型に一貫性があることを意味する場合を除きます。
ajeh

1
@ajehおよびThomas:1)「単純な」テストは、動作の違いを引き起こす変動をカバーしていないため、誤解を招くことがよくあります。2)一方が混合する際に大幅なパフォーマンスヒットを見た場合VARCHARNVARCHARの索引付けに起因すべきことであるが、VARCHAR照合の種類と一緒にカラム)その列(ひいてはインデックスに使用しました。このトピックについては、次のブログ投稿で詳しく説明します。VARCHAR型とNVARCHAR型を混在させた場合のインデックスへの影響
ソロモンルツキー2017

44

nvarcharは、メモリ、ストレージ、ワーキングセット、およびインデックス作成でかなりのオーバーヘッドが発生するので、仕様でそれが本当に必要になること決してないという場合は、気にしないでください。

多くの状況、特にASCII / EBCDICからのETLや、キーと外部キーであることが多い識別子とコード列は完全に無駄になる可能性があるため、ハードで高速な「常にnvarchar」ルールはありません。

一方、多くの列のケースがあり、私はこの質問を早めに質問し、すぐに難しい答えがすぐに得られない場合は、列をnvarcharにします。


26

すでにかなりの数があるので、私はここにさらに別の答えを追加するのをためらいますが、行われていない、または明確にされていないいくつかのポイントを作る必要があります。

最初:常に使用しないでくださいNVARCHAR。これは非常に危険であり、多くの場合コストがかかる態度/アプローチです。そして、それは「言うことは良いではありません決して、彼らは時々 、特定の問題を解決するための最も効率的な手段であり、行うための一般的な回避策ので、カーソルを使用しない」WHILEループはほとんど常により遅いだろう適切に行わカーソル。

「常に」という用語を使用する必要があるのは、「常に状況に最適なことを常に行う」ようにアドバイスするときだけです。特に、開発時間の短期的な利益(マネージャー:「この機能が必要です-今まで知らなかった-1週間前!」)と、期間のメンテナンスコスト(3週間のスプリントで3か月のプロジェクトを完了するように最初にチームに圧力をかけたマネージャー:「なぜこれらのパフォーマンスの問題が発生しているのですか?柔軟性のないXをどうしたら実行できたのでしょうか?これを修正するための1つか2つのスプリント。優先アイテムに戻すために、1週間で何ができるでしょうか?そして、これが起こらないように、設計により多くの時間を費やす必要があります!」)。

第二に、 @ gbnの回答では、パスが100%明確でない場合に特定のデータモデリングの決定を行う際に考慮すべきいくつかの非常に重要なポイントに触れています。ただし、さらに考慮すべき点があります。

  • トランザクションログファイルのサイズ
  • 複製にかかる時間(複製を使用している場合)
  • ETLにかかる時間(ETLの場合)
  • ログをリモートシステムに送信して復元するのにかかる時間(ログ配布を使用している場合)
  • バックアップのサイズ
  • バックアップの完了にかかる時間
  • 復元にかか​​る時間(これはいつか重要になるかもしれません;-)
  • tempdbに必要なサイズ
  • トリガーのパフォーマンス(tempdbに格納されている挿入および削除されたテーブルの場合)
  • 行のバージョン管理のパフォーマンス(バージョンストアがtempdbにあるため、SNAPSHOT ISOLATIONを使用している場合)
  • CFOが昨年のSANに100万ドルを費やしたばかりで、追加のストレージ用にさらに25万ドルを承認しないとCFOが言ったときに、新しいディスク領域を取得する機能
  • INSERTおよびUPDATE操作を実行するのにかかる時間の長さ
  • インデックスのメンテナンスにかかる時間
  • などなど

スペースの浪費は、システム全体に大きな影響を及ぼします。私はこのトピックの明確な詳細に入る記事を書きました:ディスクは安いです!ORLY?(無料登録が必要です。申し訳ありませんが、そのポリシーは管理できません)。

3番目:「これは小さなアプリです」という側面に誤って焦点を当てている回答もあれば、「適切なものを使用する」ことを正しく提案している回答もありますが、いずれの回答もOPに実際のガイダンスを提供していません。質問で言及された重要な詳細これは彼らの学校のウェブページであるということです。すごい!したがって、次のことを提案できます。

  • 学生や学部の名前のフィールドは、おそらくNVARCHAR他の文化の名前がそれらの場所に表示される可能性が高まるため、おそらくそうなるはずです。
  • しかし、住所や都市名についてはどうでしょうか。アプリの目的は明記されていませんが(有用だったでしょう)、住所レコードがある場合、特定の地理的領域(つまり、単一の言語/文化)のみに関係していると想定VARCHARし、適切なコードページ(フィールドの照合から決定されます)。
  • 州および/または国のISOコードを格納する場合(格納する必要はありませんINT/ TINYINTISOコードは固定長で、人間が読める形式であり、標準なので:) CHAR(2)2文字のコードとCHAR(3)3文字のコードを使用する場合に使用します。また、などのバイナリ照合順序の使用を検討してくださいLatin1_General_100_BIN2
  • 郵便番号(つまり、郵便番号)を保管する場合VARCHARは、AZ以外の文字を使用しないことが国際標準であるため、使用してください。そして、はい。VARCHAR郵便番号は数字ではなく文字列であり、一部に先行 "0"があるため、INTではなくUSの郵便番号のみを格納する場合でも使用します。また、などのバイナリ照合順序の使用を検討してくださいLatin1_General_100_BIN2
  • メールアドレスやURLを保存する場合はNVARCHAR、両方にUnicode文字を含めることができるようになったので使用します。
  • 等々....

第四:今、あなたが持っているNVARCHARデータは、多くのスペースとして二回取って、それはデータのためにする必要があるよりも、そのきれいに収まるVARCHAR(「うまくフィット」=に入らない「?」)と何とか、まるで魔法のように、アプリケーションがしたが成長現在、これらのフィールドの少なくとも1つに数百万のレコードがあり、ほとんどの行は標準のASCIIですが、一部にはUnicode文字が含まれているためNVARCHAR、保持する必要があります。以下を検討してください。

  1. SQL Server 2008-2016 RTM を使用していて、Enterprise Editionを使用している場合、またはSQL Server 2016 SP1(すべてのエディションでデータ圧縮が利用可能になった)以降を使用している場合は、データ圧縮を有効にできます。データ圧縮ではNCHARNVARCHARフィールド内のUnicodeデータを圧縮できます(ただし、「常に」ではありません)。決定要因は次のとおりです。

    1. NCHAR(1 - 4000)また、Unicodeの標準圧縮スキームをNVARCHAR(1 - 4000)使用しますが、SQL Server 2008 R2以降のみで、IN ROWデータのみで、OVERFLOWではありません。これは、通常のROW / PAGE圧縮アルゴリズムよりも優れているようです。
    2. NVARCHAR(MAX)そして、XML(と私も思いますVARBINARY(MAX)TEXTNTEXT(LOBまたはオーバーフローページでない行オフ)の行である)データ缶が少なくともPAGEは圧縮されますが、ない ROWは、圧縮されました。もちろん、PAGE圧縮は行内の値のサイズに依存します。VARCHAR(MAX)でテストしたところ、6000文字/バイトの行は圧縮されませんでしたが、4000文字/バイトの行は圧縮されました。
    3. OFF ROWデータ、LOBまたはOVERLOW =圧縮なし!
  2. SQL Server 2005、または2008-2016 RTMを使用していて、Enterprise Editionを使用していない場合VARCHAR、1つと1 つの2つのフィールドを使用できますNVARCHAR。たとえば、ほとんどすべてのベースASCII文字(値0〜127)であるため、に収まるがVARCHAR、場合によってはUnicode文字が含まれるURLを格納しているとします。スキーマには、次の3つのフィールドを含めることができます。

      ...
      URLa VARCHAR(2048) NULL,
      URLu NVARCHAR(2048) NULL,
      URL AS (ISNULL(CONVERT(NVARCHAR([URLa])), [URLu])),
      CONSTRAINT [CK_TableName_OneUrlMax] CHECK (
                        ([URLa] IS NOT NULL OR [URLu] IS NOT NULL)
                    AND ([URLa] IS NULL OR [URLu] IS NULL))
    );

    このモデルでは、計算列からSELECT するだけ[URL]です。挿入および更新の場合、変換によって入力値が変更されるかどうかを確認して、使用するフィールドを決定しますNVARCHAR

    INSERT INTO TableName (..., URLa, URLu)
    VALUES (...,
            IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL),
            IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL)
           );
  3. 着信値をGZIP VARBINARY(MAX)して、その途中で解凍できます。

    • SQL Server 2005-2014の場合:SQLCLRを使用できます。SQL#(私が書いたSQLCLRライブラリ)には、無料バージョンのUtil_GZipUtil_GUnzipが付属しています
    • SQL Server 2016以降の場合:GZipでもある組み込み関数COMPRESSDECOMPRESS関数を使用できます。
  4. SQL Server 2017以降を使用している場合は、テーブルをクラスター化列ストアインデックスにすることを検討できます。

  5. これはまだ実行可能なオプションではありませんが、SQL Server 2019ではVARCHAR/ CHARデータ型にUTF-8のネイティブサポートが導入されています。現在、それを使用するにはバグが多すぎますが、修正されている場合、これは一部のシナリオではオプションです。この新機能の詳細な分析については、投稿「SQL Server 2019でのネイティブUTF-8サポート:救世主か偽預言者か?」を参照してください。


7
スロークラップ。「常にnvarcharを使用する」が140票を得たことに単に驚いたが、これはそうではなかった。この投稿での素晴らしい仕事。
schizoid04 2017年

1
@ schizoid04ありがとう。公正を期すために、承認された回答は私の7年前に投稿されたので、再評価するために戻ってきなかった多くのトラフィック(および/または他のさまざまな人)が投票しました。それでも、投票ベースのフォーラムを推進する「群衆の知恵」理論に対する非常に強固な対抗点を提供します。誤解が多すぎます。たとえば、これはDBA.SEです。私が投稿する前に受け入れられたもう1つの回答は、最も狭い定義で誤解を招く「正しい」ものであり、私が私の中で反証する情報が含まれていますが、それでも私のものを上回っています。
ソロモンルツキー2017年

22

アプリケーションでは、データベースのサイズが小さいため、nvarcharで十分です。「常にnvarcharを使用する」と言うのは非常に単純化しすぎです。漢字やその他のクレイジーキャラクターなどを格納する必要がない場合は、VARCHARを使用すると、使用するスペースが大幅に少なくなります。現在の仕事の前任者は、NVARCHARが不要なときにそれを使用して何かを設計しました。私たちは最近それをVARCHARに切り替え、そのテーブルだけで15 GBを節約しました(高度に書き込まれました)。さらに、そのテーブルにインデックスがあり、その列を含めたり、複合インデックスを作成したりする場合は、インデックスファイルのサイズを大きくしただけです。

ただ、慎重に判断してください。SQL開発とデータ定義では、「デフォルトの答え」はめったにないようです(もちろん、カーソルをすべてのコストで避けてください)。


10

アプリケーションが小さいので、基本的にはvarcharよりもnvarcharを使用してもそれほど大きなコストの増加はありません。Unicodeデータを保存する必要がある場合は、潜在的な頭痛の種を省くことができます。


8

一般的に言えば、制約が最も少ない最も高価なデータ型から始めます。それを生産に入れなさい。パフォーマンスが問題になり始めたら、それらのnvarchar列に実際に何が格納されているかを調べます。そこに収まらない文字はありvarcharますか?そうでない場合は、varcharに切り替えます。痛みがどこにあるかがわかる前に、事前に最適化しようとしないでください。私の推測では、nvarcharとvarcharのどちらを選択するかによって、将来的にアプリケーションの速度が低下することはありません。パフォーマンスチューニングはあなたにはるかに与えるアプリケーションの他の部分があるでしょうドルのための強打を


7

その過去数年間、これらのプロジェクトはすべて多言語対応であるため、すべてのプロジェクトでNVARCHARを使用しています。外部ソース(ASCIIファイルなど)からインポートされたデータは、データベースに挿入される前にUnicodeにアップコンバートされます。

大きなインデックスなどから、パフォーマンス関連の問題はまだ発生していません。インデックスはより多くのメモリを使用しますが、メモリは安価です。

ストアドプロシージャを使用するか、その場でSQLを構築するかに関係なく、すべての文字列定数の前にNを付けます(例:SET @foo = N'Hello world。 ';)。したがって、定数もUnicodeです。これにより、実行時の文字列型変換が回避されます。

YMMV。


4
おそらく、作業しているテーブルに数億レコードはありません。ほとんどのアプリでは、デフォルトでnvarcharに設定すれば問題ありませんが、すべてではないことに同意します。
ブランドンムーア2012年

7

私はこれについての経験から話すことができますnvarchar。絶対に必要でない限り、このデータフィールドタイプは、より大きなデータベースのパフォーマンスを破壊します。性能とスペースの面で痛かったデータベースを引き継ぎました。30 GBのデータベースのサイズを70%削減できました。パフォーマンスを向上させるために行われた他の変更がいくつかありましたが、もそれによってvarchar大幅に改善されたと確信しています。データベースにテーブルを100万以上に拡張する可能性がある場合、レコードは絶対に避けてくださいnvarchar


4

私は仕事でこの質問をよく扱います:

  • 在庫と価格のFTPフィード-varcharが正常に機能したとき、アイテムの説明とその他のテキストはnvarcharにありました。これらをvarcharに変換すると、ファイルサイズがほぼ半分になり、アップロードに役立ちました。

  • 上記のシナリオは、誰かがアイテムの説明に特殊文字を入れるまでうまく機能しました(おそらく商標で、覚えられません)

私はまだvarcharよりも毎回nvarcharを使用しません。特殊文字の疑いや可能性がある場合は、nvarcharを使用します。ほとんどの場合、フィールドに入力するものを100%制御しているときにvarcharを使用しています。


3

このすべての議論で、UTF-8の言及がないのはなぜですか?文字のユニコードスパン全体を格納できるということは、文字ごとに2バイト(またはUNICODE用語を使用するための「コードポイント」)を常に割り当てる必要があるという意味ではありません。ASCIIはすべてUTF-8です。SQL ServerはVARCHAR()フィールドをチェックして、テキストが厳密なASCII(つまり、上位バイトビットがゼロ)であることを確認しますか?望みません。

そして場合は、ユニコードを保存したい古いASCIIのみのアプリケーションとの互換性が欲しい、私は魔法の弾丸のようになりVARCHAR()とUTF-8を使用したと思うだろう:それだけ、それはする必要があるより多くのスペースを使用しています。

UTF-8に慣れていない方のために、入門書をお勧めます。


2
提案していることは一部のアプリケーションでは機能する可能性がありますが、SQLテキストの処理方法に対する追加のエンコーディングレイヤーの影響も考慮する必要があります。特に、照合、検索、およびパターンマッチングが実行されます。また、レポートがデータベースに対して実行される場合、標準のレポートツールはマルチバイト文字を正しく操作しません。また、一括インポートおよび一括エクスポートが影響を受ける場合があります。私は、長期的には、このスキームは価値があるよりも厄介であると思います。
Jeffrey L Whitledge、2009

1
UTF-8をVARCHAR列に格納することはできません。MSSQLは常に UTF-8データを列照合に変換します。照合順序をめちゃくちゃにする場合(CP1252をLatin_1に格納しようとするなど)、変換は機能せず、データに余分なバイトが含まれます。latin_1を(アプリ側で)UTF-8に変換し、再度latin_1(db側)に戻すと正常に動作するように見えるかもしれませんが、それは単なる幻想です。freetdsを使用し、プロトコルを7未満に設定することで、DBが列の照合に自動変換してスニークできますが、nvarcharをクエリする機能は失われます。
チュガディー2013

1
@chugadieとTevya:この答えは少し無意味ではありません。SQL Serverは、UCS-2 / UTF-16のみを使用してUnicodeデータ(つまり、XMLおよび- N接頭辞付きタイプ)を格納します。UTF-8を使用するという選択肢はありません。また、Unicodeエンコーディング(UTF-8、UCS-2 / UTF-16、UTF-32)はVARCHARフィールドに適用できません。
ソロモンルツキー

2

特定のセットの文字が含まれないようにデータ型を意図的に制限したい場合は、例外的な例があります。たとえば、ドメイン名をデータベースに格納する必要があるシナリオがありました。ドメイン名の国際化は当時は信頼できなかったので、ベースレベルで入力を制限し、潜在的な問題を回避するのに役立ちました。


1

NVARCHARシステムストアドプロシージャがそれを必要とするだけで使用していて、最も頻繁に発生するのが不可解sp_executesqlであり、動的SQLが非常に長い場合は、パフォーマンスの観点からすべての文字列操作(連結、置換など)を行ってVARCHARから変換する方が良いでしょう。最終結果はNVARCHAR、それをprocパラメータに渡します。したがって、常に使用しないでくださいNVARCHAR

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.