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のライブ放送機能の詳しい説明

推薦する

Vue3 の ref toRef と toRefs の違いを理解する方法

目次1. 基本1.参照2. 参照3. 参照4. 最適な使い方2. 詳細な1. なぜrefが必要なのか...

CSS の clip-path プロパティの使用方法の詳細な説明

クリップパスの使用ポリゴン値は複数の座標点で構成されます。最初の値は x 方向、2 番目の値は y ...

VueでTypeScriptを使用する方法

導入近年、TypeScript を求める声がますます高まり、TypeScript はフロントエンドに...

DockerコンテナのIPアドレスを取得する方法の詳細な説明

1.コンテナに入った後 /etc/hosts を cat するコンテナ自体の IP アドレスと (-...

MySql データベース クエリの特殊コマンド

まずMySQLのインストールMySQLソフトウェアをダウンロードし、インストールパスを変更しますMy...

MySQL 更新セットとの違い

目次問題の説明原因分析解決問題の説明最近、奇妙な問い合わせを受けました。更新ステートメントはエラーな...

WeChatアプレットがフォーム検証を実装

WeChatアプレットフォームの検証、参考までに具体的な内容は次のとおりです。プラグインWxVali...

Linux でファイアウォールがオフになっているかどうかを確認する方法

1. サービス方法ファイアウォールのステータスを確認します。 [root@centos6 ~]# サ...

MySQL共通ストレージエンジンの機能と使用方法の詳細な説明

この記事では、一般的な MySQL ストレージ エンジンの機能と使用方法を例を使って説明します。ご参...

JSON.stringify のさまざまな用途のまとめ

序文json を使用したことがある人なら、オブジェクトを文字列化してからバックエンドに送信するのが一...

CSS3 レーダースキャンマップのサンプルコード

CSS3 を使用して、クールなレーダースキャン画像を実現します。 コード上で直接: // インデック...

Docker を使用した nGrinder パフォーマンス テスト プラットフォームの導入プロセスの分析

nGrinderとは何ですか? nGrinder は、スクリプトの作成、テストの実行、監視、結果レポ...

select count() と select count(1) の違いと実行方法

Count(*) または Count(1) または Count([column]) は、おそらく S...

Vue 要素と Nuxt の使用に関するヒントを共有する

1. 要素時間選択提出フォーマット変換例えば 2018年9月7日金曜日 00:00:00 GMT+0...

Linux lseek関数の使い方の詳しい説明

注:記事に誤りがある場合は、メッセージを残して指摘してください。ご協力ありがとうございます。名前名前...