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

推薦する

はじめに: HTML の基本的なタグと属性の簡単な紹介

HTML はタグと属性で構成されており、これらを組み合わせてブラウザにページの表示方法を指示します。...

JavaScript 基礎シリーズ: 関数とメソッド

目次1. 関数とメソッドの違い2. 良い関数の書き方2.1 正確な命名2.1.1 関数の命名2.1....

Linux Cron によるパラメータ付き PHP コードのスケジュール実行

1. 引き続き PHP スクリプトを使用して実行します。コマンドラインに入力: php /home/...

ウェブページの右側に固定されたフローティングレイヤーの実装コード

コードをコピーコードは次のとおりです。 <!DOCTYPE html PUBLIC "...

JavaScript ESの新機能letとconstキーワードに基づく

目次1. letキーワード1.1 基本的な使い方1.2 変動昇進はない1.3 一時的なデッドゾーン1...

CentOS7 に YUM 経由で MySQL 5.7 をインストールする詳細な手順

1. インストールパッケージを保存する場所に移動しますcd /home/lnmp 2. MySQL ...

VirtualBox でのホストオンリー + NAT モードのネットワーク構成

VirtualBoxのHost Only+NATモードのネットワーク構成は参考用です。具体的な内容は...

初心者のための HTML コーディングガイドライン 30 選

1. HTMLタグは常に閉じる前のページのソース コードでは、次のような記述がよく見られます。 &l...

マインスイーパゲームを実装するための jQuery プラグイン (2)

この記事では、jQueryプラグインを使用してマインスイーパゲームを実装する2番目の記事を参考までに...

LinuxベースのSelenium環境を構成し、操作を実装する

1. Linux で Selenium を使用する1. Chromeをインストールする次のコマンドを...

Chrome 73 によるフレックスレイアウトの崩れの解析と解決方法

現象プロジェクトにはネストされたフレックス構造がいくつかあります。 <スタイル> /* ...

MySQL 文字セットの表示と変更のチュートリアル

1. 文字セットを確認する1. MYSQLデータベースサーバーとデータベースの文字セットを確認する方...

入力タグの名前と値の違い

type はブラウザでの入力と出力に使用されるコントロールです (たとえば、type="t...

Oracle Rownum 書き込みに似た MySQL の詳細な例

Rownum は、Oracle での独自の書き込み方法です。Oracle では、rownum を使用...

JSは写真の自動再生効果を実現します

この記事では、写真の自動再生効果を実現するためのJSの具体的なコードを参考までに紹介します。具体的な...