SQL Server データ型の varchar と nvarchar の主なパフォーマンスの違いは何ですか?
-
09-06-2019 - |
質問
私は学校で以下を使用して小さな Web アプリのデータベースに取り組んでいます。 SQL Server 2005
.
この問題に関してはいくつかの学派があると思います。 varchar
対 nvarchar
:
- 使用
varchar
多くの国際化されたデータを扱う場合を除き、次を使用します。nvarchar
. - ただ使用してください
nvarchar
全てにおいて。
ビュー 2 の利点が見え始めています。nvarchar が 2 倍のスペースを必要とすることはわかっていますが、これは数百人の生徒のデータを保存するだけなので、必ずしも大したことではありません。私にとっては、それを気にせず、すべてに nvarchar を使用できるようにするのが最も簡単なように思えます。それとも何か足りないものがあるのでしょうか?
解決
常に nvarchar を使用してください。
ほとんどのアプリケーションでは 2 バイト文字が必要になることはありません。ただし、2 バイト言語をサポートする必要があり、データベース スキーマで 1 バイトのみがサポートされている場合、アプリケーション全体に戻って変更するのは非常にコストがかかります。
1 つのアプリケーションを varchar から nvarchar に移行するコストは、ほとんどのアプリケーションで使用するわずかな追加ディスク容量よりもはるかに高くなります。
他のヒント
ディスク容量は問題ではありません...しかし、記憶力とパフォーマンスはそうなります。ページ読み取り量が 2 倍、インデックス サイズが 2 倍、奇妙な LIKE と = 一定の動作など
中国語などのスクリプトを保存する必要がありますか?はい、もしくは、いいえ...
そしてMS BOLからは」Unicode のストレージとパフォーマンスへの影響"
編集:
nvarchar のパフォーマンスがいかに悪くなる可能性があるかを強調する最近の SO の質問...
一貫性を保ちましょう!VARCHAR を NVARCHAR に JOIN すると、パフォーマンスに大きな影響が生じます。
nvarchar は、メモリ、ストレージ、ワーキング セット、インデックス作成において大幅なオーバーヘッドを持つことになるため、仕様で実際にオーバーヘッドが規定されている場合は、 一度もない 必要なことなので、気にしないでください。
多くの状況、特に ASCII/EBCDIC からの ETL や、キーや外部キーであることが多い識別子やコード列など、完全に無駄になる可能性があるため、厳密で迅速な「常に nvarchar」ルールはありません。
一方、列の場合は必ず早めに質問し、すぐに明確な答えが得られなかった場合は列を nvarchar にするケースがたくさんあります。
データベースのサイズが小さいため、アプリケーションの場合は nvarchar で十分です。「常に nvarchar を使用する」というのは、非常に単純化しすぎです。漢字やその他の特殊な文字のようなものを保存する必要がない場合は、VARCHAR を使用してください。使用するスペースが大幅に少なくなります。私の現在の職場の前任者は、NVARCHAR が必要でないときに NVARCHAR を使用して何かを設計しました。最近、VARCHAR に切り替えて、そのテーブルだけで 15 GB を節約しました (書き込み量が多かった)。さらに、そのテーブルにインデックスがあり、その列を含める、または複合インデックスを作成する場合は、インデックス ファイルのサイズが大きくなるだけです。
慎重に決定してください。SQL 開発とデータ定義では、「デフォルトの答え」が存在することはほとんどないようです (もちろん、何としてもカーソルを避けることは別ですが)。
すでにかなりの数があるため、ここでさらに別の回答を追加することは躊躇しますが、まだ行われていない、または明確にされていない点についていくつか指摘する必要があります。
初め: する ない いつも使う NVARCHAR
. 。それは非常に危険で、多くの場合コストがかかる態度/アプローチです。「」と言うのは良いことではありません。一度もない カーソルは特定の問題を解決する最も効率的な手段である場合があり、カーソルを使用する場合の一般的な回避策であるためです。 WHILE
ループはほとんどの場合、 きちんと 完了カーソル。
「常に」という言葉を使用する必要があるのは、「常に状況に応じて最善のことを行う」ようにアドバイスする場合です。確かに、特に開発時間の短期的な利益とのバランスをとろうとする場合には、それを判断するのが難しいことがよくあります (マネージャー:「この機能が必要です -- つい最近まで知らなかったのです -- 1 週間前です!」) 長期的なメンテナンスコストがかかります (最初に 3 か月のプロジェクトを 3 週間のスプリントで完了するようチームに圧力をかけたマネージャー) :「なぜこのようなパフォーマンスの問題が発生するのでしょうか?柔軟性のない X をどうやって実行できたのでしょうか?これを修正するのに 1 ~ 2 回のスプリントを費やす余裕はありません。優先事項に戻るために、1 週間で何を終わらせることができるでしょうか?そして、このようなことが今後も起こらないように、設計により多くの時間を費やす必要があります!」)。
2番目: @gbnの回答は、パスが100%明確でない場合に特定のデータモデリングの決定を行う際に考慮すべき非常に重要な点について触れています。しかし、さらに考慮すべきことがあります。
- トランザクション ログ ファイルのサイズ
- レプリケーションにかかる時間 (レプリケーションを使用する場合)
- ETL にかかる時間 (ETL の場合)
- ログをリモート システムに送信して復元するのにかかる時間 (ログ配布を使用する場合)
- バックアップのサイズ
- バックアップが完了するまでにかかる時間
- 復元にかかる時間 (これはいつか重要になるかもしれません ;-)
- tempdb に必要なサイズ
- トリガーのパフォーマンス (tempdb に保存されている挿入および削除されたテーブルの場合)
- 行のバージョン管理のパフォーマンス (バージョン ストアが tempdb にあるため、SNAPSHOT ISOLATION を使用している場合)
- CFO が、昨年 SAN に 100 万ドルを費やしたばかりなので、追加のストレージとしてさらに 25 万ドルを承認しないと言ったときに、新しいディスク領域を取得する機能
- INSERT および UPDATE 操作の実行にかかる時間の長さ
- インデックスのメンテナンスにかかる時間
- などなど
無駄なスペースには、 巨大な システム全体へのカスケード効果。私はこのトピックについて明確に詳しく説明した記事を書きました。 ディスクが安い!オルリー? (無料登録が必要です。申し訳ありませんが、私はそのポリシーを管理できません)。
三番目: 一部の回答は「これは小さなアプリである」という側面に誤って焦点を当てており、また一部は「適切なものを使用する」ことを正しく示唆していますが、どの回答も O.P. に真の指針を提供していません。質問で言及されている重要な詳細は、これが学校の Web ページであるということです。素晴らしい!したがって、次のように提案できます。
- 学生名および/または教員名を入力するフィールドは次のとおりです。 おそらく なれ
NVARCHAR
なぜなら、時間の経過とともに、他の文化の名前がそれらの場所に現れる可能性が高まるだけだからです。 - しかし、番地や都市名についてはどうでしょうか?アプリの目的は述べられていませんでしたが(あれば助かったでしょう)、住所記録があれば、特定の地理的地域だけに関係していると想定しています(つまり、単一の言語/文化) を使用する場合は、
VARCHAR
適切なコード ページ (フィールドの照合順序から決定されます) を使用します。 - 州および/または国の ISO コードを保存する場合 (保存する必要はありません)
INT
/TINYINT
ISO コードは固定長であり、人間が判読でき、標準的なものであるため :) を使用します。CHAR(2)
2 文字コードの場合とCHAR(3)
3文字コードを使用する場合。そして、次のようなバイナリ照合順序の使用を検討してください。Latin1_General_100_BIN2
. - 郵便番号を保存する場合 (例:郵便番号)、使用します
VARCHAR
A ~ Z 以外の文字は決して使用しないことが国際標準だからです。そしてはい、まだ使用していますVARCHAR
郵便番号は数字ではなく文字列であり、先頭に「0」を持つものがあるため、INT ではなく米国の郵便番号のみを保存する場合でも、そして、次のようなバイナリ照合順序の使用を検討してください。Latin1_General_100_BIN2
. - 電子メール アドレスや URL を保存する場合は、次を使用します。
NVARCHAR
どちらにも Unicode 文字を含めることができるようになったためです。 - 等々....
第4: これで、 NVARCHAR
データは、適切に収まるデータに必要なスペースの 2 倍のスペースを占有します。 VARCHAR
(「うまくフィットする」 = 「?」にならない) そしてどういうわけか、まるで魔法のようにアプリケーションは成長し、今ではこれらのフィールドの少なくとも 1 つに何百万ものレコードが存在します。 ほとんど 行は標準 ASCII ですが、一部には Unicode 文字が含まれているため、 NVARCHAR
, 、次の点を考慮してください。
SQL Server 2008 ~ 2016 RTM を使用している場合 そして Enterprise Edition を使用している場合、または SQL Server 2016 SP1 (すべてのエディションでデータ圧縮が利用可能になった) 以降を使用している場合は、有効にすることができます。 データ圧縮. 。データ圧縮は、Unicode データを圧縮できます (ただし、「常に」圧縮できるわけではありません)。
NCHAR
そしてNVARCHAR
田畑。決定要因は次のとおりです。NCHAR(1 - 4000)
そしてNVARCHAR(1 - 4000)
使用 Unicode の標準圧縮スキーム, ただし、SQL Server 2008 R2 以降のみであり、OVERFLOW ではなく IN ROW データのみが対象です。これは、通常の ROW / PAGE 圧縮アルゴリズムよりも優れているようです。NVARCHAR(MAX)
そしてXML
(そして私もそう思いますVARBINARY(MAX)
,TEXT
, 、 そしてNTEXT
) IN ROW (LOB または OVERFLOW ページのオフローではない) データは、少なくとも PAGE 圧縮できますが、 ない ROW が圧縮されました。もちろん、PAGE 圧縮は行内の値のサイズに依存します。VARCHAR(MAX) でテストしたところ、6000 文字/バイトの行は圧縮されませんが、4000 文字/バイトの行は圧縮されることがわかりました。- OFF ROW データ、LOB または OVERLOW = 圧縮なし!
SQL Server 2005、または 2008 ~ 2016 RTM を使用している場合、 ない Enterprise Edition では、次の 2 つのフィールドを指定できます。1つ
VARCHAR
そして1つNVARCHAR
. 。たとえば、ほとんどすべての基本 ASCII 文字 (値 0 ~ 127) である URL を保存しているとします。VARCHAR
, 、ただし Unicode 文字が含まれる場合もあります。スキーマには次の 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)) );
このモデルでは、 のみ から選択します
[URL]
計算された列。挿入と更新の場合、変換によって受信値が変更されるかどうかを確認して、どのフィールドを使用するかを決定します。NVARCHAR
タイプ:INSERT INTO TableName (..., URLa, URLu) VALUES (..., IIF (CONVERT(VARCHAR(2048), @URL) = @URL, @URL, NULL), IIF (CONVERT(VARCHAR(2048), @URL) <> @URL, NULL, @URL) );
受信した値を GZIP で圧縮できます。
VARBINARY(MAX)
そして、途中で解凍します。- SQL Server 2005 ~ 2014 の場合:SQLCLR を使用できます。 SQL# (私が書いた SQLCLR ライブラリ) が付属しています Util_GZip そして Util_GUnzip 無料版では
- SQL Server 2016 以降の場合:組み込みを使用できます
COMPRESS
そしてDECOMPRESS
これらの関数も GZip です。
SQL Server 2017 以降を使用している場合は、テーブルをクラスター化列ストア インデックスにすることを検討できます。
これはまだ実行可能なオプションではありませんが、SQL Server 2019 では UTF-8 のネイティブ サポートが導入されています。
VARCHAR
/CHAR
データ型。現時点ではバグが多すぎて使用できませんが、それらが修正されれば、これはオプションになります。 いくつかの シナリオ。私の投稿をご覧ください。」SQL Server 2019 でのネイティブ UTF-8 サポート:救世主か偽預言者か?この新機能の詳細な分析については、「」を参照してください。
アプリケーションは小さいため、基本的に varchar よりも nvarchar を使用しても目立ったコストの増加はなく、Unicode データを保存する必要がある場合に将来的に頭の痛い問題が発生する可能性はありません。
一般的に言えば;制約が最も少なく、最も高価なデータ型から始めます。 本番環境に導入する. 。パフォーマンスが問題になり始めた場合は、実際に何が保存されているかを調べてください。 nvarchar
列。当てはまらない文字はありますか varchar
?そうでない場合は、varchar に切り替えます。どこに問題があるのかを知る前に、事前最適化を試みないでください。私の推測ではそれです nvarchar と varchar のどちらを選択してもアプリケーションの速度が低下するわけではありません 近い将来に。アプリケーションの他の部分でも、パフォーマンスをチューニングすることでさらに多くの効果が得られるでしょう。 お買い得.
これらのプロジェクトはすべて多言語であるため、ここ数年間、すべてのプロジェクトであらゆることに NVARCHAR を使用してきました。外部ソースからインポートされたデータ (例:ASCII ファイルなど) は、データベースに挿入される前に Unicode にアップコンバートされます。
大きなインデックスなどによるパフォーマンス関連の問題はまだ発生していません。インデックスはより多くのメモリを使用しますが、メモリは安価です。
ストアド プロシージャを使用するか、オンザフライで SQL を構築するかにかかわらず、すべての文字列定数の先頭に N が付いていることを確認してください (例:SET @foo = N'Hello world.';) したがって、定数も Unicode です。これにより、実行時の文字列型変換が回避されます。
YMMV。
これについては経験から言えますが、気をつけてください nvarchar
. 。どうしても必要な場合を除き、このデータ フィールド タイプは大規模なデータベースのパフォーマンスを破壊します。引き継いだデータベースは、パフォーマンスとスペースの点で問題がありました。30 GB のデータベースのサイズを 70% 削減することができました。パフォーマンスを向上させるために他にもいくつかの変更が加えられましたが、 varchar
もそれに関して大きく役立ちました。データベースにテーブルが 100 万個まで増加する可能性がある場合、レコードは次のようなものにならないようにしてください。 nvarchar
何としても。
私は職場でよくこの質問に答えます。
在庫と価格の FTP フィード - varchar が正常に動作していた場合、商品説明やその他のテキストは nvarchar でした。これらを varchar に変換すると、ファイル サイズがほぼ半分に減り、アップロードが非常に楽になりました。
上記のシナリオは、誰かが商品説明に特殊文字 (おそらく商標、思い出せません) を入力するまでは正常に機能しました。
私はまだ、varchar ではなく nvarchar を毎回使用するわけではありません。特殊文字に疑問や可能性がある場合は、nvarchar を使用します。私が varchar を使用するのは、主にフィールドに設定されている内容を 100% 制御している場合です。
この議論の中で、UTF-8 についてまったく言及されなかったのはなぜですか?文字の完全な Unicode スパンを格納できるということは、常に 1 文字あたり 2 バイト (UNICODE 用語を使用する場合は「コード ポイント」) を割り当てる必要があるという意味ではありません。ASCII はすべて UTF-8 です。SQL Server は、VARCHAR() フィールドのテキストが厳密な ASCII であるかどうかをチェックしますか (つまり、上位バイトのビット 0)?そうならないことを願っています。
Unicodeを保存したい場合 そして 古い ASCII のみのアプリケーションとの互換性が必要な場合は、VARCHAR() と UTF-8 を使用することが特効薬になると思います。必要な場合にのみ、より多くのスペースを使用します。
UTF-8 に慣れていない人には、次をお勧めします。 プライマー.
例外的に、データ型を意図的に制限して確実にデータ型を制限したい場合があります。 しません 特定のセットの文字が含まれています。たとえば、ドメイン名をデータベースに保存する必要があるシナリオがありました。当時、ドメイン名の国際化は信頼できなかったため、基本レベルで入力を制限し、潜在的な問題を回避する方が賢明でした。
使用している場合 NVARCHAR
システム ストアド プロシージャがそれを必要とするという理由だけで、最も頻繁に発生するのは不可解な場合です sp_executesql
, 、動的 SQL が非常に長い場合、パフォーマンスの観点から、すべての文字列操作 (連結、置換など) を で実行する方が良いでしょう。 VARCHAR
最終結果を次のように変換します NVARCHAR
そしてそれを proc パラメータに入力します。いいえ、常に使用しないでください NVARCHAR
!