SQL Server 2019で「nvarchar / nchar」が使用されるのはいつですか?


11

SQL Serverの2019 Microsoftが紹介してUTF-8サポートCHARVARCHARデータ型をと言います:

この機能により、使用中の文字セットによっては、ストレージを大幅に節約できる場合があります。たとえば、UTF-8対応の照合を使用して、ASCII文字列を含む既存の列データ型をNCHAR(10)からCHAR(10)に変更すると、ストレージ要件が約50%削減されます。この削減は、NCHAR(10)がストレージに22バイトを必要とするのに対し、CHAR(10)は同じUnicode文字列に12バイトを必要とするためです。

UTF-8は、ように見えるサポートので、基本的に私たちがUnicodeデータを格納し始めることができ、すべてのスクリプトをvarcharしてchar列。また、ドキュメントで述べられているように、これによりテーブルとインデックスのサイズを削減でき、そこから読み取るデータの量が少ないため、パフォーマンスがさらに向上します。

これは、UTF-16を実装する列nvarcharnchar列の使用を停止できることを意味しているのでしょうか。

誰かがシナリオと理由を指摘できますUTFか?エンコーディングでcharデータ型を使用せず、n-chars データ型を引き続き使用しますか?


テストして報告してみませんか?また、nvarcharからvarcharに変換するために費やした労力、変更テーブルにかかった時間、テストに費やした時間、発生した問題もお知らせください。
Colin 't Hart

@ Colin'tHart既知の問題や考慮事項がない場合は、データの移行を計画しています。データの読み取りが少ないほど、システムのパフォーマンスが向上するからです。変換について-もちろん、指定された列のインデックスがある場合は特に時間がかかります-再構築する必要がありますが、うまくいくと思います。もちろん、すぐにパフォーマンスへの影響をテストし、移行が不要になる問題を探します。
gotqn 2018

SQL Serverは、PAGEまたはROW圧縮を使用する場合、NVarchar列のUnicode圧縮をサポートすることに注意してください。 docs.microsoft.com/en-us/sql/relational-databases/...
デイビット・ブラウン-マイクロソフト

1
「ASCIIのようなデータ」を格納している場合、UTF-8はスペースを節約する可能性がありますが、それ自体は圧縮ではないため、そのように誤解しないでください。たとえば、主に中国語の名前をデータベースに保存している場合CHAR、Unicode型よりもUTF-8 型を使用するほうが得策です(圧縮の有無にかかわらず、最終的にデータを処理するには圧縮を解除する必要があるため)。また、Windowsのネイティブ文字列タイプはUnicodeであるため、UTF-8文字列をデコードする必要があることがよくあります。関連するトレードオフは、Nタイプがすぐに廃止される可能性が低いことを意味します。
Jeroen Mostert、2018

1
CHARエンジンが文字列を直接UTF-8として処理するためのネイティブサポートをエンジンが取得する場合、UTF-8の#1 "キラーアプリ" はおそらくLinux上のSQL Serverです-ここでUTF-8は(多かれ少なかれ) "ネイティブ"文字セットですそして、UTF-16として文字列を保持することは、あまり効率的ではありません。CHAR保存できる文字を制限する照合は魅力的ではなかったので、Windowsで既に使用している場所で使用しても害はありません。
Jeroen Mostert、2018

回答:


6

これにより、テーブルとインデックスのサイズを減らすことができます(強調を追加)

場合のサイズの削減のみ可能ですほとんどの文字は基本的に[space]0 - 9A - Za - z、およびいくつかの基本的な句読点。その特定の文字セット(実際の使用条件では、標準のASCII値32〜126)以外では、せいぜいサイズはNVARCHAR/ UTF-16 と同じか、多くの場合それより大きくなります。

読み取るデータが少なくなるとシステムのパフォーマンスが向上するので、データの移行を計画しています。

注意してください。UTF-8は魔法の「すべて修正」スイッチではありません。他のすべての条件が同じである場合は、そうです。読む回数が少ないとパフォーマンスが向上します。しかし、ここで「他のすべてのもの」は等しくありません。標準のASCII文字のみを格納する場合でも(つまり、すべての文字が1バイトであるため、に格納する場合と比べて必要なスペースが半分ですNVARCHAR)、UTF-8を使用するとパフォーマンスが若干低下します。問題はUTF-8が可変長エンコーディングであるためであると考えています。つまり、完全な文字であるか、または次のバイトがその一部であるかを確認するために、各バイトを読み取るときに解釈する必要があります。つまり、すべての文字列操作は最初から始まり、バイトごとに進む必要があります。一方、NVARCHAR / UTF-16は常に2バイト(補足文字も2つの2バイトコードポイントで構成されます)であるため、すべてを2バイトのチャンクで読み取ることができます。

私のテストでは、標準のASCII文字だけでも、データをUTF-8として保存しても経過時間を節約できませんでしたが、CPU時間は明らかに低下しました。そしてそれはデータ圧縮なしだったので、少なくとも使用されたディスクスペースは少なくなりました。しかし、圧縮を使用すると、UTF-8に必要なスペースは1%から1.5%だけ小さくなりました。つまり、UTF-8の場合、実質的にスペースを節約することなく、CPU時間を長くすることができます。

NVARCHAR(MAX)Unicode圧縮は、その値が行に格納できるほど小さい場合でも、そのデータ型では機能しないため、使用すると状況がさらに複雑になります。ただし、データが十分に小さい場合でも、行またはページ圧縮のメリットが得られます(この場合、実際にはUTF-8よりも高速になります)。ただし、行外データは圧縮を使用できません。それでも、テーブルをクラスター化列ストアインデックスにすると、サイズが大幅に削減されますNVARCHAR(MAX)(クラスター化列ストアインデックスを使用するときにUTF-8よりも少し大きい場合でも)。

誰でもシナリオと理由を指摘できますが、UTFエンコーディングでcharデータ型を使用しないでください

間違いなく。実際、ほとんどの場合それを使用するやむを得ない理由は本当にわかりません。UTF-8から本当にメリットがある唯一のシナリオは次のとおりです。

  1. データは主に標準のASCII(値0〜127)
  2. Unicodeである必要があります。これは、単一の8ビットコードページ(つまりVARCHAR)で利用可能な文字よりも広い範囲の文字を格納する必要がある可能性があるためです。
  3. ほとんどのデータはオフローで保存されます(そのため、ページ圧縮は機能しません)
  4. クエリパフォーマンス以外の理由でサイズを削減する必要がある/したい十分なデータがある(バックアップサイズの削減、バックアップ/復元に必要な時間の削減など)
  5. クラスター化列ストアインデックスは使用できません(この場合、テーブルを使用するとパフォーマンスが低下する可能性があります)。

私のテストでは、ほとんどすべてのケースで、特にデータが多い場合にNVARCHARの方が高速であったことが示されています。実際、1行あたり平均5k 文字の 21k行には、UTF-8で165 MB、NVARCHAR非圧縮で236 MBが必要でした。それでも、NVARCHAR経過時間は2倍高速で、CPU時間も少なくとも2倍高速(場合によってはそれ以上)でした。それでも、ディスク上でさらに71 MBを消費しました。

それ以外では、少なくともCTP 2以降はUTF-8を使用することはお勧めしません。この機能で見つかったさまざまなバグが原因です。

UTF-16とUTF-8の違いの説明を含むこの新機能の詳細な分析、およびそれらのバグのリストについては、私の投稿を参照してください。

SQL Server 2019でのネイティブUTF-8サポート:救世主か偽預言者か?


12

UTF-8サポートにより、新しいオプションのセットが提供されます。潜在的なスペース節約(行またはページの圧縮なし)は1つの考慮事項ですが、タイプとエンコードの選択は、主に比較、並べ替え、データのインポート、およびエクスポートの実際の要件に基づいて行われる必要があります

たとえば、nchar(1)型は2バイトのストレージを提供するため、想像以上に変更する必要がある場合があります。これは、BMP(コードポイント000000〜00FFFF)に任意の文字を格納するのに十分です。その範囲の一部の文字はUTF-8で1バイトだけでエンコードされますが、その他の文字は2バイトまたは3バイトを必要とします(詳細については、この比較表を参照してください)。したがって、UTF-8で同じ文字セットを確実にカバーするには、が必要ですchar(3)

例えば:

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 char(1) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

おなじみのエラーを出します:

メッセージ8152、レベル16、状態30、行xxx
文字列またはバイナリデータは切り捨てられます。

または、トレースフラグ460がアクティブな場合:

メッセージ2628、レベル16、状態1、行xxx
文字列またはバイナリデータは、テーブル '@T'、列 'UTF8'で切り捨てられます。切り捨てられた値: ''。

UTF8列を拡張するchar(2)varchar(2)、次のエラーを解決しますNCHAR(911)

DECLARE @T AS table 
(
    n integer PRIMARY KEY,
    UTF16 nchar(1) COLLATE Latin1_General_CI_AS,
    UTF8 varchar(2) COLLATE Latin1_General_100_CI_AS_SC_UTF8
);

INSERT @T (n, UTF16, UTF8)
SELECT 911, NCHAR(911), NCHAR(911);

ただし、たとえばの場合NCHAR(8364)、列をchar(3)またはにさらに拡張する必要がありますvarchar(3)

UTF-8照合順序はすべて補助文字を使用するため、レプリケーションでは機能ないことにも注意してください。

それ以外の点を除けば、UTF-8サポートは現時点ではプレビュー段階にあるため、本番環境では使用できません。

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