utf8_general_ciとutf8_unicode_ciの違いは何ですか?


1063

との間utf8_general_ciutf8_unicode_ci、パフォーマンスの点で違いはありますか?



6
あなたが好きならutf8[mb4]_unicode_ci、あなたはあり好きutf8[mb4]_unicode_520_ciもっと。
リックジェームズ

8
私はそれについてどう感じているのかわかりません。最新のUnicode標準に従うように実装を修正する代わりに、古いバージョンをデフォルトとして維持しているため、適切なバージョンを使用するには「520」を追加する必要があります。また、古いバージョンのMySQLでは「520」バージョンを使用できないため、上位互換性および下位互換性はありません。既存の照合を更新できなかったのはなぜですか?本当に「mb4」と同じです。それをデフォルトとして維持することを正当化するために、どのコードが古い、制限された/廃止された動作に実際に依存していたのですか?
thomasrutter 2017

7
さらに良いのは、8.0のデフォルトのutf8mb4_0900_ai_ciです。
リックジェームズ

回答:


1591

これら2つの照合順序は、どちらもUTF-8文字エンコーディング用です。違いは、テキストのソート方法と比較方法です。

注:MySQL utf8mb4では、ではなくを使用する必要がありますutf8。紛らわしいことに、utf8これは下位互換性のためにのみ残されている初期のMySQLバージョンからの欠陥のあるUTF-8実装です。修正バージョンには名前が付けられましたutf8mb4

注:MySQLの新しいバージョンでは utf8mb4_0900_ai_ci 、Unicode 9.0に基づく同等のルール などの名前で利用可能なUnicodeの並べ替えルールが更新され、同等の_general バリアント はありませんこれを読んでいる人は、おそらく、_unicode またはの 代わりに、これらの新しい照合順序の1つを使用する必要があります_general代わりに新しい照合順序の1つを使用できる場合、以下に記載されている内容の多くは、あまり関心がありません。

主な違い

  • utf8mb4_unicode_ci は、幅広い言語で正確に並べ替えられるユニバーサルな並べ替えと比較のための公式のUnicodeルールに基づいています。

  • utf8mb4_general_ciは、速度を向上させるために設計された多くのショートカットを実行しながら、できることと同じように実行することを目的とした並べ替えルールの簡略化されたセットです。これはUnicode規則に準拠していないため、特定の言語や文字を使用する場合など、状況によっては望ましくない並べ替えや比較が行われます。

    最近のサーバーでは、このパフォーマンスの向上はほとんど無視できます。サーバーが今日のコンピュータのCPUパフォーマンスのごく一部を占めていたときに考案されました。

utf8mb4_unicode_ci以上のメリットutf8mb4_general_ci

utf8mb4_unicode_ciは、並べ替えと比較にUnicodeルールを使用し、さまざまな言語で、さまざまな特殊文字を使用するときに、かなり複雑なアルゴリズムを使用して正しい並べ替えを行います。これらのルールでは、言語固有の規則を考慮する必要があります。誰もが「アルファベット順」と呼ぶもので文字を並べ替えるわけではありません。

ラテン語(つまり「ヨーロッパ」)言語に関する限りutf8mb4_general_ci、MySQLのUnicodeソートと単純化されたソートには大きな違いはありませんが、いくつかの違いがあります。

  • たとえば、Unicode照合では、「ss」のように「ß」と「OE」のように「Œ」をutf8mb4_general_ciソートしますが、それらの文字を使用する人々は通常必要とするのに対し、それらを単一の文字としてソートします(それぞれ「s」と「e」のようです)。 。

  • 一部のUnicode文字は無視できるものとして定義されています。つまり、並べ替え順序にカウントされず、比較は次の文字に移ります。 utf8mb4_unicode_ciこれらを適切に処理します。

ラテン語以外の言語(アジア言語や異なるアルファベットの言語など)では、Unicodeの並べ替えと簡略化された並べ替えの間にさらに多くの違いがある場合がありますutf8mb4_general_ci。の適合性はutf8mb4_general_ci、使用する言語に大きく依存します。一部の言語では、それは非常に不十分です。

何を使うべきですか?

utf8mb4_general_ciパフォーマンスの違いが重要になるほどCPU速度が遅いという点を残しているので、使用する理由はほとんどありません。データベースは、これ以外のボトルネックによってほぼ確実に制限されます。

以前はutf8mb4_general_ci、パフォーマンスコストを正当化するために正確なソートが重要である場合を除いて、一部の人々は使用を推奨しました。今日、そのパフォーマンスコストはほとんどなくなっており、開発者は国際化をより真剣に扱っています。

正確さよりも速度を重視する場合は、並べ替えをまったく行わない方がよいという主張があります。正確である必要がない場合は、アルゴリズムを高速化するのは簡単です。したがって、utf8mb4_general_ci速度上の理由からおそらく不要であり、おそらく精度上の理由からも適切ではない妥協案です。

さらにもう1つ、アプリケーションが英語のみをサポートしていることがわかっていても、他の言語で使用されている文字が含まれていることがよくあるため、正しくソートすることが重要です。 。すべてにUnicodeルールを使用すると、非常に賢いUnicodeの人々が並べ替えを適切に機能させるために非常に一生懸命に取り組んできたので、安心が得られます。

パーツの意味

1つ目ciは、大文字と小文字を区別しない並べ替えと比較です。これは、テキストデータに適していることを意味し、大文字と小文字は重要ではありません。他のタイプの照合はcs、大文字と小文字が区別されるテキストデータの場合(大文字と小文字が区別されます)bin、エンコーディングが一致する必要がある場合はビットごとに行われます。これは、実際にエンコードされたバイナリデータ(たとえば、 Base64)。大文字と小文字を区別する並べ替えは、奇妙な結果につながり、大文字と小文字を区別する比較では、大文字と小文字のみが異なる重複値が生じる可能性があるため、大文字と小文字を区別する照合は、テキストデータでは優先されません。などもおそらく重要であり、バイナリ照合がより適切な場合があります。

次に、unicodeまたはgeneral特定の並べ替えおよび比較ルールを参照します-特に、テキストが正規化または比較される方法。そこutf8mb4文字エンコーディングのための規則の多くの異なるセットをして、あるunicodegeneral考えられるすべての言語ではなく、ある特定の1でうまく動作するように2つのという試みています。これらの2つのルールセットの違いは、この回答の主題です。unicodeはUnicode 4.0のルールを使用していることに注意してください。MySQLの最近のバージョンではunicode_520、Unicode 5.2のルールを使用してルールセットを追加し、0900(「unicode_」の部分を削除して)Unicode 9.0のルールを使用しています。

そして最後に、utf8mb4もちろん内部的に使用される文字エンコーディングです。この回答では、Unicodeベースのエンコーディングについてのみ話しています。


218
@KahWeeTengあなたは必要があります決して、今まで使用utf8_general_ci:それは単に動作しません。それは、50年前からのASCII stooopeeedityの古き良き時代の先祖返りです。Unicodeの大文字と小文字を区別しない一致は、UCDからの折りたたみマップなしでは実行できません。たとえば、「Σίσυφος」には3つの異なるシグマがあります。または、「TSCHüẞ」の小文字は「tschüβ」ですが、「tschüβ」の大文字は「TSCHÜSS」です。あなたは正しいことができる、またはあなたは速いことができます。したがって、を使用する必要がありますutf8_unicode_ci。正確さを気にしない場合は、無限に高速にするのは簡単です。
tchrist

7
これを読んだ後、私はutf8_unicode_ciが同じ比較ウェイトを持つ文字を等しい比較のために等しいと見なすことも明らかにしました。これは例につながります"か" == "が""ǽ" == "æ"。ソートにはこれは理にかなっていますが、等式を使用して選択したり、一意のインデックスを処理したりすると驚くかもしれません-bugs.mysql.com/bug.php?id=16526
Mat Schaffer

4
@DanHorvat MySQLの古い、制限されたUnicodeのサブセットに制限する唯一の実用的な理由は、より完全なutf8mb4をサポートしない古いバージョンのMySQLを使用している場合です。5.5.3は5歳以上です。Pleskは別のMySQLスケジュールで実行されますが、ほとんどのディストリビューションは現在MySQL 5.5にあり、コンポーネントを更新した場合、Plesk 11.x MySQL 5.5をサポートします。
thomasrutter

22
新しい、より標準に準拠したバージョンを使用することは悪い習慣であることに私は同意しません。このようなことで人々を悪い開発者と呼ぶのは扇情的だと思います。また、私の答えは、「MySQLの新しいバージョンでは、utf8ではなくutf8mb4を使用する」と強調していることに注意してください。
thomasrutter 2015年

24
@DanHorvat utf8mb4唯一の正しい選択です。ではutf8、あなただけのMySQL(およびMariaDB)というUTF8のいくつかのMySQLのみ、3バイトの変種で立ち往生していると何をすべきか知っています。その他の国ではUTF8を使用しており、1文字あたり最大4バイトを含めることができます。MySQL開発者は、自作のエンコーディングの名前を誤ってutf8おり、下位互換性を壊さないように、実際のUTF8をとして参照する必要がありますutf8mb4
Stijn de Witt

162

私が使用して性能差が何であるかを知りたいと思ったutf8_general_ciutf8_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

次に、次のストアドプロシージャを作成して、simple SELECTSELECTwith LIKE、sorting(SELECT with 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回ずつ照合するための各ストアドプロシージャ5回コールutf8_general_ciおよび5回utf8_unicode_ci)、次いで、平均値を算出しました。

私の結果は:

benchmark_simple_select()

  • utf8_general_ci:9,957ミリ秒
  • utf8_unicode_ci:10,271ミリ秒

このベンチマークでは、使用utf8_unicode_ciutf8_general_ci3.2%より遅いです。

benchmark_select_like()

  • utf8_general_ci:11,441ミリ秒
  • utf8_unicode_ci:12,811ミリ秒

このベンチマークでは、使用utf8_unicode_ciutf8_general_ci12%より遅いです。

benchmark_order_by()

  • utf8_general_ci:11,944ミリ秒
  • utf8_unicode_ci:12,887ミリ秒

このベンチマークでは、使用utf8_unicode_ciutf8_general_ci7.9%より遅いです。


16
素晴らしいベンチマーク、共有してくれてありがとう。よく似た数値(Windows上のMySQL v5.6.12)を取得しています:10%、4%、8%。私は同意します:のパフォーマンスの向上は、utf8_general_ci使用するには価値がありません。
RandomSeed 2013

10
1)しかし、このベンチマークは、定義上、2つの照合に対して同様の結果を生成するべきではないでしょうか?CONV(FLOOR(RAND() * 99999999999999), 20, 36)つまり、ASCIIのみを生成し、照合のアルゴリズムで処理されるUnicode文字は生成しません。2)Description = 'test' COLLATE ...Description LIKE 'test%' COLLATE ...、実行時にのみ単一の文字列(「テスト」)を処理し、しない彼らは?3)実際のアプリでは、順序付けに使用される列にはおそらくインデックスが付けられ、実際の非ASCIIテキストとの異なる照合でのインデックス作成速度は異なる場合があります。
HalilÖzgür2014年

2
@HalilÖzgür-あなたの主張は部分的に間違っています。私はそれが外にASCIIを(general_ciを正しく扱うことになる)ことにするコードポイント値ではないだと思うが、「UMLのように書かウムラウト治療などの特定の機能に関するEA UTE」またはそのようないくつかの微妙なと。
Tomasz Gandor 2015

38

この投稿はそれを非常にうまく説明しています。

つまり、utf8_unicode_ciは、Unicode標準で定義されているUnicode照合アルゴリズムを使用しますが、utf8_general_ciは、より単純な並べ替え順序であり、結果として「精度が低く」なります。


1
ありがとう。それが私の印象でした。私はパフォーマンスヒットをとります:)
onassar

7
正確さを気にしない場合は、アルゴリズムを無限に高速にするのは簡単です。使用utf8_unicode_ciして、もう一方が存在しないふりをするだけです。
tchrist

1
@tchristしかし、正確さと速度の間の特定のバランスが気にutf8_general_ciなるなら、あなたのためかもしれません
シェルバク

@tchristゲームプログラマーにならない;)
Stijn de Witt

1
@onassar-MySQL 8.0は、すべての照合のパフォーマンスを大幅に向上させると主張しています。
リックジェームズ

9

mysqlマニュアルの「Unicode Character Sets」セクションを参照してください。

Unicode文字セットの場合、_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セットはより高速になります。


18
「少し正確ではない」というようなものはありません。正確性はブール特性です。学位の修飾子は認められません。utf8_unicode_ciバグのある壊れたバージョンが存在しないふりをするだけです。
tchrist

2
collat​​ion_connection設定を取得するために5.6.15を取得する際に問題が発生し、「SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci」のようなSET行で渡す必要があることがわかりました。クレジットは、解決策としてMathias Bynensに提供されます。彼の非常に役立つガイドは次のとおり
Steve Hibbert

4
@tchrist正しさはブール値であると言うことの問題は、それが絶対的な正しさに依存しない状況を考慮に入れていないことです。あなたの根本的なポイントは無効ではなく、general_ciの利点を支持しようとしていますが、正当性に関するあなたの一般的な声明は簡単に反証されます。私は自分の職業で毎日それをしています。コメディはさておき、スチュアートはここで良い点を持っています
Anthony

5
ジオロケーションまたはゲーム開発では、正確さとパフォーマンスを常に交換します。もちろん、正確性は0との間の実数1であり、boolではありません。:) EGがバウンディングボックスでジオポイントを選択することは、「近くのポイント」の近似であり、ポイントと参照ポイントの間の距離を計算し、それをフィルタリングすることほど良くありません。しかし、どちらも概算であり、実際には、完全な正確さはほとんど達成できません。海岸線のパラドックスIEEE 754を
Stijn de Witt 2016

4
TL; DR正しい結果を出力するプログラムを提供してください1/3
Stijn de Witt

7

簡単に言えば:

より良い並べ替え順序が必要な場合-使用 utf8_unicode_ci(これが推奨される方法です)、

ただし、パフォーマンスに完全に関心がある場合は、 utf8_general_ciしますが、少し古いことを知っています。

パフォーマンスの違いはごくわずかです。


1
どちらも現在は古くなっています。詳しくは、承認された回答をご覧ください
thomasrutter

OK、ありがとう@thomasrutter
simhumileco

6

いくつかの詳細(PL)

ここで読むことができるように(Peter Gulutzan)ポーランド語の文字 "Ł"(L with stroke-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です。このコーディングのどれも良くも悪くもありません-それはあなたのニーズに依存します。


1

並べ替えと文字一致には2つの大きな違いがあります。

並べ替え

  • utf8mb4_general_ci すべてのアクセントを削除し、1つずつ並べ替えます。これにより、正しくない並べ替え結果が作成される可能性があります。
  • utf8mb4_unicode_ci 正確に並べ替えます。

文字マッチング

キャラクターのマッチングは異なります。

たとえば、utf8mb4_unicode_ciあなたはを持っていますがi != ıutf8mb4_general_ciそれを保持していますı=i

たとえば、の行があるとしname="Yılmaz"ます。その後

select id from users where name='Yilmaz';

コロケーションがの場合は行を返しますがutf8mb4_general_ci、コロケーションされてutf8mb4_unicode_ciいる場合は行を返しません

一方、それはありますがa=ªß=ssutf8mb4_unicode_ciは当てはまりませんutf8mb4_general_ci。でname="ªßi"、次の行があるとします。

select id from users where name='assi';

コロケーションがの場合は行を返しますがutf8mb4_unicode_ci、コロケーションがに設定されている場合は行を返しませんutf8mb4_general_ci

コロケーションごとの一致の完全なリストは、こちらで確認できます


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