MySQL では UTF-8 が推奨されないのはなぜですか?

MySQL では UTF-8 が推奨されないのはなぜですか?

最近、Rails 経由で「utf8」でエンコードされた UTF-8 文字列を MariaDB に保存しようとしたときに、奇妙なエラーが発生するというバグに遭遇しました。

不正な文字列値: '\xF0\x9F\x98\x83、行 1 の列 'summary'

クライアント、サーバー、データベースではUTF-8エンコードを使用しています。文字列「

問題の核心は、MySQL の「utf8」が実際には真の UTF-8 ではないことです。

「utf8」は 1 文字あたり最大 3 バイトしかサポートしませんが、真の UTF-8 は 1 文字あたり最大 4 バイトをサポートします。

MySQL はこのバグを修正せず、2010 年にこの問題を回避する「utf8mb4」という文字セットをリリースしました。

もちろん、彼らは新しい文字セットを広く宣伝しませんでした (おそらくこのバグが彼らを恥ずかしい思いをさせたため)。そのため、開発者はインターネット上で依然として「utf8」を使用するようにアドバイスされていますが、これらの提案は間違っています。

簡単な要約は次のとおりです。

MySQL の「utf8mb4」は真の「UTF-8」です。

MySQL の「utf8」は、いくつかの Unicode 文字のみをエンコードできる「独自のエンコーディング」です。

ここで明確にしておきたいのは、「utf8」を使用しているすべての MySQL および MariaDB ユーザーは、「utf8mb4」に切り替えて、「utf8」を二度と使用しないでください。

では、エンコーディングとは何でしょうか? UTF-8とは何ですか?

コンピューターがテキストを保存するために 0 と 1 を使用することは誰もが知っています。たとえば、文字「C」が「01000011」として保存されている場合、コンピューターはこの文字を表示するために次の 2 つの手順を実行する必要があります。

  1. コンピュータは「01000011」を読み取り、67 という数字を取得します。これは、67 が「01000011」としてエンコードされているためです。
  2. コンピュータは Unicode 文字セットで 67 を検索し、「C」を見つけます。

同様に:

  1. 私のコンピューターは、「C」を Unicode 文字セットの文字 67 にマッピングします。
  2. 私のコンピュータは 67 を「01000011」としてエンコードし、Web サーバーに送信します。

ほとんどすべての Web アプリケーションでは、他の文字セットを使用する理由がないため、Unicode 文字セットが使用されます。

Unicode 文字セットには数百万の文字が含まれています。最も単純なエンコードは UTF-32 で、文字ごとに 32 ビットを使用します。コンピュータは常に 32 ビットを数値として認識しており、数値の計算が得意であるため、これを実行するのが最も簡単です。しかし問題は、これによってスペースが無駄になりすぎることです。

UTF-8 はスペースを節約できます。UTF-8 では、文字「C」に必要なのは 8 ビットだけですが、「」などの一部の一般的でない文字には 32 ビットが必要です。その他の文字では 16 ビットまたは 24 ビットが使用される場合があります。この記事のような記事は、UTF-8 を使用してエンコードすると、UTF-32 の約 4 分の 1 のスペースしか占有しません。

MySQL の「utf8」文字セットは他のプログラムと互換性がありません。「utf8」と呼ばれるものは、実際には...

MySQLの簡単な歴史

MySQL 開発者が「utf8」を無効にするのはなぜでしょうか?コミットログから答えが見つかるかもしれません。

MySQL は 2003 年のバージョン 4.1 から UTF-8 をサポートしており、現在使用されている UTF-8 標準 (RFC 3629) はその後登場しました。

古い UTF-8 標準 (RFC 2279) では、文字あたり最大 6 バイトがサポートされます。 2002 年 3 月 28 日、MySQL 開発者は MySQL 4.1 の最初のプレビュー リリースで RFC 2279 を使用しました。

同年 9 月、MySQL ソース コードに調整が加えられました。「UTF8 は現在、最大 3 バイトのシーケンスのみをサポートします。」

このコードを送信したのは誰ですか?彼はなぜそんなことをしたのですか?この質問に対する答えは不明です。 Git に移行した後 (MySQL は元々 BitKeeper を使用していました)、MySQL コードベースのコミッターの名前の多くが失われました。 2003 年 9 月のメーリング リストには、この変更を説明できる手がかりはありません。

しかし、推測してみることはできます。

2002 年に、MySQL は、ユーザーがデータ テーブルの各行で同じバイト数を使用することを保証できれば、MySQL のパフォーマンスを大幅に向上できるという決定を下しました。これを行うには、ユーザーはテキスト列を「CHAR」として定義する必要があります。各「CHAR」列の文字数は常に同じです。挿入された文字数が定義された数より少ない場合、MySQL はスペースで埋めます。挿入された文字数が定義された数を超える場合、超過分は切り捨てられます。

MySQL 開発者が最初に UTF-8 を試したとき、文字ごとに 6 バイトが使用され、CHAR(1) では 6 バイト、CHAR(2) では 12 バイトなどが使用されます。

当初の動作は正しかったと言えますが、残念ながらこのバージョンはリリースされていません。しかし、それは文書に書かれており、広く流布されています。UTF-8 を理解する人なら誰でも、文書に書かれていることに同意します。

しかし、MySQL の開発者やメーカーは、ユーザーが次の 2 つのことを行うのではないかと懸念していることは明らかです。

CHAR を使用して列を定義します (現在では CHAR は古い形式ですが、当時は MySQL の方が高速でしたが、2005 年以降はそうではありません)。
CHAR 列のエンコードを「utf8」に設定します。
私の推測では、MySQL 開発者は、スペースと速度の両方でメリットのあるものを求めるユーザーを支援したかったのですが、「utf8」エンコーディングを台無しにしてしまったのです。

つまり、結果は勝者なしです。スペースと速度の両方のメリットを期待するユーザーは、「utf8」で CHAR 列を使用すると、実際には予想よりも多くのスペースが使用され、予想よりも遅くなることを感じる場合があります。また、正確性を求めるユーザーは、「utf8」エンコーディングを使用すると、「」のような文字を保存できません。

この不正な文字セットがリリースされた後、MySQL はすべてのユーザーにデータベースの再構築を依頼しない限り、これを修正できませんでした。最終的に、MySQL は真の UTF-8 をサポートするために 2010 年に「utf8mb4」として再リリースされました。

なぜこの問題は人々をそんなに狂わせるのでしょうか? この問題のせいで、私は丸一週間狂っていました。私は「utf8」に騙され、バグを見つけるのに多くの時間を費やしました。しかし、私だけがそう思っているわけではないことは確かです。Web 上のほぼすべての記事では、「utf8」を実際の UTF-8 として扱っています。

「utf8」は単なる独自の文字セットであり、解決されていない新たな問題を引き起こします。

要約する

MySQL または MariaDB を使用している場合は、「utf8」エンコードを使用せず、代わりに「utf8mb4」を使用してください。ここでは、既存のデータベースの文字エンコードを「utf8」から「utf8mb4」に変換するためのガイドが提供されます。

**元の英語テキスト:**https://medium.com/@adamhooper/in-mysql-never-use-utf8-use-utf8mb4-11761243e434

以下もご興味があるかもしれません:
  • MySQL データベースで UTF-8 エンコードを設定する方法
  • MySQL で UTF-8 エンコーディングを使用しないのはなぜですか?
  • MySQL GBK → UTF-8 エンコーディング変換

<<:  HTML チュートリアル、optgroup 要素の理解

>>:  Vueのライブ放送機能の詳しい説明

推薦する

React ルーティング リンク構成の詳細

1. 属性へのリンク(1)ルーティングパスを配置する(2)指定された形式でオブジェクトを配置する{パ...

MySQLが正常にインストールされたかどうかを確認する方法

MySQL をインストールした後、DOS ウィンドウまたは MySQL 5.7 コマンドライン クラ...

JavaScript 配列 sort() メソッドの基本的な使い方と落とし穴

序文日常のコード開発では、配列のソートに関連する操作が多数あります。JavaScript では、so...

Kubernetes コントローラーとラベルの簡単な分析

目次01 k8sの一般的なコントローラーRCコントローラーデプロイメント コントローラーステートフル...

mysql の find_in_set 関数の基本的な使い方

序文これは私が最近見つけた新しい機能です。プロジェクトでの私の使用シナリオは次のとおりです。アプリケ...

Linux で MySQL 5.6 X64 バージョンをインストールする詳細な手順

環境: 1. CentOS6.5 X64 2.mysql-5.6.34-linux-glibc2.5...

CSS コンテナ背景 10 色グラデーション デモ (linear-gradient())

文法 背景: linear-gradient(direction,color-stop1,color...

Dockerは同じIPネットワークセグメントとの接続を実現する

最近、Docker とホストが同じネットワーク セグメント上で通信する問題を解決し、そのプロセス全体...

mysql update文の実行プロセスの詳細な説明

以前、MySQL クエリ文の実行プロセスについての記事がありました。ここでは、更新文の実行プロセスを...

この記事では、6つの負荷分散技術の実装方法をまとめます(要約)

ロード バランシングは、サーバー クラスタの展開でよく使用されるデバイスです。マシンのパフォーマンス...

MySQL全文インデックスの原理と欠点

MySQL フルテキスト インデックスは、特定のテーブルの特定の列に表示されるすべての単語のリストを...

MySQL でテーブル メタデータ ロックを待機する理由と方法

MySQL が alter table などの DDL 操作を実行すると、テーブル メタデータ ロッ...

パゴダパネルとドッカーを使用して Gogs をインストールするプロセス全体

目次1 Baota Software StoreにDockerをインストールする2 ゴグスイメージを...

CSS で縦書きテキスト配置を実装する方法 (概要)

HTML でのテキストのデフォルトの配置は水平ですが、特殊な場合にはテキストを垂直に配置する必要が...

Ubuntu環境にAnaconda3をインストールするための完全な手順

目次Anaconda の紹介1. ダウンロード1.1 インストールパッケージを保存するフォルダを作成...