utf8_general_ciと
utf8_unicode_ci` では、性能面で何か違いがありますか?
この2つの照合順序は、どちらも文字コードUTF-8のためのものです。 違いは、テキストのソートと比較の方法です。
Note: utf8
ではなく、utf8mb4
を使用する必要があります。 どちらも UTF-8 エンコードを指しますが、古い utf8
には MySQL 固有の制限があり、0xFFFD より大きな文字が使用できません。
*注意: 新しいバージョンの MySQL では、Unicode 9.0 に基づくルールとして utf8mb4_0900_ci
のような名前で利用できる、アップデートされた Unicode ソートルールがあります - そして同等の general
バリアントはありません。
**主な相違点
utf8mb4_unicode_ci
は、ユニバーサルソートと比較のための公式ユニコード規則に基づいており、幅広い言語で正確にソートします。utf8mb4_general_ci
は簡略化されたソートルールで、スピードを向上させるために多くのショートカットをしながら、できる限りうまくやることを目的としています。 これは Unicode の規則には従っておらず、特定の言語や文字を使用する場合など、状況によっては望ましくない並べ替えや比較になることがあります。
最新のサーバーでは、この性能向上はほとんど無視できる程度でしょう。 これは、サーバーのCPU性能が今日のコンピューターのごく一部であった時代に考案されたものです。
注意: 現在では utf8mb4_unicode_ci
の更新版として utf8mb4_0900_ai_ci
があります - これは Unicode バージョン 9.0 の変更に基づいており、また明らかに高速化されています。 これは、新しい命名法を採用しており、0900
はUnicodeバージョン、ai
はアクセント非感受性を意味します - 以前の utf8mb4_unicode_ci
のように、文字中のアクセントは重要視されません。
utf8mb4_unicode_ci
と utf8mb4_general_ci
の違い
ソートと比較にユニコードのルールを使用する utf8mb4_unicode_ci
は、広範囲の言語と広範囲の特殊文字を使用するときに正しいソートを行うために、かなり複雑なアルゴリズムを採用しています。これらのルールは、言語固有の慣習を考慮する必要があります。誰もが、私たちが 'アルファベット順と呼ぶような方法で文字を並べ替えるわけではありません。
ラテン語(つまりヨーロッパ言語)に関しては、Unicode のソートと MySQL の簡略化された utf8mb4_general_ci
ソートの間に大きな違いはありませんが、まだいくつかの相違点が残っています。utf8mb4_general_ci
はこれらを単一の文字(おそらくそれぞれ "s" と "e" )としてソートします。はこれらを適切に処理します。 アジア言語や異なるアルファベットを持つ言語のような非ラテン言語では、Unicodeソートと簡略化された
utf8mb4_general_ciソートの間に多くの**差異があるかもしれません。 utf8mb4_general_ci
が適切であるかどうかは、使用する言語に大きく依存します。 ある言語では、utf8mb4_general_ci
は非常に不十分なものでしょう。
何を使うべきでしょうか?
CPU の速度が低く、性能の違いが重要であるような段階を過ぎているため、もう utf8mb4_general_ci
を使用する理由はほとんどないでしょう。 データベースはこれ以外のボトルネックによって制限されることはほぼ間違いないでしょう。
過去には、パフォーマンスコストを正当化できるほど正確なソートが重要な場合を除き、 utf8mb4_general_ci
を使用することを推奨する人もいました。 今日、このパフォーマンスコストはほとんどなくなっており、開発者は国際化をより真剣に扱うようになっています。
もし正確さよりもスピードが重要であれば、ソートをしない方が良いという議論もあります。 正確さを求めないのであれば、アルゴリズムを高速化することは些細なことです。 したがって、utf8mb4_general_ci
は、速度の理由ではおそらく必要なく、精度の理由でもおそらく適切でない妥協案です。
もうひとつ付け加えると、たとえアプリケーションが英語しかサポートしていないことがわかっていても、人名を扱う必要があるかもしれません。 このような場合、Unicodeのルールを使用することで、非常に賢いUnicodeの人々が、ソートが正しく動作するように懸命に働いてくれているという安心感を得ることができます。
各パーツの意味
まず、ci
は 大文字小文字を区別しない ソートと比較のためのものです。 つまり、テキストデータに適しており、大文字と小文字の区別は重要ではありません。 他の照合順序は、大文字と小文字を区別するテキストデータ用の cs
と、エンコーディングをビット単位で一致させる必要があるフィールド用の bin
です(たとえば Base64 などのバイナリデータ)。 大文字小文字を区別してソートすると奇妙な結果になり、大文字小文字を区別して比較すると、文字の大文字小文字が異なるだけの重複した値になることがあるので、大文字小文字を区別する照合順序はテキストデータでは好まれません。大文字小文字が重要であれば、それ以外の無視できる句読点等もおそらく重要で、バイナリ照合がより適切かもしれません。
次に、unicode
または general
は、特定のソートや比較のルール、特にテキストを正規化したり比較したりする方法を指します。 utf8mb4 の文字コードにはさまざまなルールがあり、その中でも unicode
と general
は、特定の言語ではなく、あらゆる言語でうまく動作するように試みられています。 この2つのルールの違いが、この解答の主題です。 unicodeは Unicode 4.0 のルールを使用していることに注意してください。 最近の MySQL のバージョンでは、Unicode 5.2 のルールを使用する
unicode520と Unicode 9.0 のルールを使用する
0900` ("unicode" の部分を削除) というルールセットを追加しています。
そして最後に、utf8mb4
はもちろん内部で使われている文字エンコーディングです。 この回答では、Unicodeベースのエンコーディングについてだけ話しています。utf8_general_ci
と utf8_unicode_ci
の使用のパフォーマンスの違いを知りたいのですが、インターネットに記載されているベンチマークが見つからなかったので、自分でベンチマークを作成することにしました。
500,000行の非常にシンプルなテーブルを作成しました。
CREATE TABLE test(
ID INT(11) DEFAULT NULL,
Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;
次に、この保存された手順を実行して、ランダムなデータを入力しました。
CREATE PROCEDURE randomizer()
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE random CHAR(20) ;
theloop: loop
SET random = CONV(FLOOR(RAND() * 99999999999999), 20, 36);
INSERT INTO test VALUES (i+1, random);
SET i=i+1;
IF i = 500000 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END
次に、単純な「SELECT」、「SELECT」、「LIKE」、およびソーティング(「SELECT」と「ORDER BY」)をベンチマークするために、次の格納された手順を作成しました。
CREATE PROCEDURE benchmark_simple_select()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE Description = 'test' COLLATE utf8_general_ci;
SET i = i + 1;
IF i = 30 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
CREATE PROCEDURE benchmark_select_like()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE Description LIKE '%test' COLLATE utf8_general_ci;
SET i = i + 1;
IF i = 30 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
CREATE PROCEDURE benchmark_order_by()
BEGIN
DECLARE i INT DEFAULT 0;
theloop: loop
SELECT *
FROM test
WHERE ID > FLOOR(1 + RAND() * (400000 - 1))
ORDER BY Description COLLATE utf8_general_ci LIMIT 1000;
SET i = i + 1;
IF i = 10 THEN
LEAVE theloop;
END IF;
END LOOP theloop;
END;
上記の保存された手順では、「utf8_general_ci」照合が使用されますが、もちろんテスト中に「utf8_general_ci」と「utf8_unicode_ci」の両方を使用しました。
保存された各手順を照合ごとに5回( utf8_general_ci
の場合は5回、utf8_unicode_ci
の場合は5回)呼び出し、平均値を計算しました。
私の結果は:です。
benchmark_simple_select()
。
utf8_general_ci
の場合:9,957ミリ秒。utf8_unicode_ci
の場合:10,271ミリ秒。このベンチマークでは、「utf8_unicode_ci」を使用すると、「utf8_general_ci」よりも3.2%遅くなります。
benchmark_select_like()
。
utf8_general_ci
の場合:11,441ミリ秒。utf8_unicode_ci
の場合:12,811ミリ秒。このベンチマークでは、「utf8_unicode_ci」を使用すると、「utf8_general_ci」よりも12%遅くなります。
benchmark_order_by()
。
utf8_general_ci
の場合:11,944ミリ秒。utf8_unicode_ci
の場合:12,887ミリ秒。このベンチマークでは、「utf8_unicode_ci」を使用すると、「utf8_general_ci」よりも7.9%遅くなります。
mysqlマニュアルのUnicode Character Setsの項を参照してください。
任意の Unicode 文字セットについて。 を使って行われる操作です。 general_ci 照合順序は _unicode_ci 照合順序よりも高速になります。 例えば、_general_ci照合順序の比較は、_unicode_ci照合順序の比較よりも高速です。 utf8_general_ci 照合順序はより高速です。 と比べて、正確さは若干劣りますが utf8_unicode_ciの比較。その理由は その理由は utf8_unicode_ciは、以下のようなマッピングをサポートしています。 つまり、1つの と等しいと比較されます。 他の文字との組み合わせ。例えば 例えば、ドイツ語や他のいくつかの言語では ß」は「ss」と同じです。 utf8_unicode_ciは、以下の項目もサポートしています。 短縮形と無視できる文字。 utf8_general_ci はレガシー照合順序です。 拡張をサポートしていません。 短縮形、無視できる文字。 1対1のみ可能です。 文字間の比較を行います。
つまり、要約すると、utf_general_ci は、標準全体を実装する べき である utf_unicode_ci よりも小さくて (標準に従って) 正しくない比較のセットを使用します。general_ci のセットは、行うべき計算がより少ないので、より速くなります。
簡単に言えば:。
より良い並べ替え順序が必要な場合は、「utf8_unicode_ci」を使用します(これが推奨される方法です)。
ただし、パフォーマンスにまったく興味がある場合は、「utf8_general_ci」を使用しますが、少し古いことに注意してください。
パフォーマンスの違いは非常にわずかです。
詳細(PL)。 -。
[ここ]2を読むことができるように、ポーランド文字「 ⁇ 」(ストローク付きL-html esc: Ł
)の並べ替え/比較に違いがあります(小文字: "ł"-html esc: ł
)-次の仮定があります。
utf8_polish_ci Ł greater than L and less than M
utf8_unicode_ci Ł greater than L and less than M
utf8_unicode_520_ci Ł equal to L
utf8_general_ci Ł greater than Z
洗練された言語では、文字「 ⁇ 」は文字「L」の後、「M」の前です。 このコーディングのどれも良くも悪くもありません-それはあなたのニーズに依存します。
[2]:https://bugs.mysql.com/bug.php?id = 9604%20%E2%80%93%20user3399549%20Mar%209%20%2714%20at%2021:15。