SQL Server 2019で、MicrosoftはCHAR
およびVARCHAR
データ型に TF-8サポート を導入し、次のように述べています。
この機能により、使用中の文字セットによっては、ストレージを大幅に節約できる場合があります。たとえば、UTF-8対応の照合を使用してASCII文字列をNCHAR(10)からCHAR(10)に変更して既存の列データ型を変更すると、ストレージ要件が約50%削減されます。これは削減は、NCHAR(10)がストレージに22バイトを必要とするのに対し、CHAR(10)は同じUnicode文字列に12バイトを必要とするためです。
UTF-8は support すべてのスクリプトと思われるので、基本的にはvarchar
列とchar
列にUnicodeデータの格納を開始できます。ドキュメントで述べられているように、これによりテーブルとインデックスのサイズを削減でき、そこから読み取られるデータの量が少なくなるため、パフォーマンスがさらに向上します。
これは、UTF-16を実装するnvarchar
およびnchar
列の使用を停止できることを意味しているのでしょうか。
誰かがシナリオと理由を指摘できますか?UTF
エンコーディングでcharデータ型を使用せず、n-charsのものを引き続き使用しますか?
これcanテーブルとインデックスのサイズを小さくします(強調を追加)
サイズの削減は、文字のmostが本質的に_[space]
_、_0 - 9
_、_A - Z
_、_a - z
_、およびいくつかの基本的な句読点。その特定の文字セット(実際の使用条件では、標準ASCII値32〜126)の外では、サイズはせいぜい等しくなりますNVARCHAR
/UTF-16、または多くの場合それよりも大きい。
読み取るデータが少なくなるとシステムのパフォーマンスが向上するので、データの移行を計画しています。
注意してください。 UTF-8は魔法の「すべてを修正する」スイッチではありません。他のすべての条件が同じである場合は、はい、読んだ回数が少なくてもパフォーマンスは向上します。しかし、ここで「他のすべてのもの」は等しくない。 のみを格納する場合でも標準ASCII文字(つまり、すべての文字は1バイトであるため、NVARCHAR
)、UTF-8を使用するとパフォーマンスが若干低下します。UTF-8が可変長エンコーディングであるため、問題が発生するのは、各バイトを読み取るときに解釈する必要があることを意味します。それが完全な文字である場合、または次のバイトがその一部である場合。これは、すべての文字列操作が最初から始まり、バイトごとに進む必要があることを意味します。一方、NVARCHAR
/UTF -16は常に2バイト(補足文字も2バイトの2バイトコードポイントで構成されます)なので、すべてを2バイトチャンクで読み取ることができます。
私のテストでは、only標準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から本当にメリットがある唯一のシナリオは次のとおりです。
VARCHAR
)で使用できるよりも広い範囲の文字を格納する必要があるため、Unicodeである必要があります。私のテストでは、ほとんどすべてのケースで、特にデータが多い場合に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の違いの説明を含むこの新機能の詳細な分析、およびそれらのバグのリストについては、私の投稿を参照してください。
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サポートは現時点ではプレビュー段階にあるため、本番環境では使用できません。