38738
**utf8mb4について**  
・誰がどこで決めた仕様？  
・ISOか何かで文字コード体系として決まっているのでしょうか？  
・それとも、MySQL独自の仕様？

**バイト数について**  
・「日本語1文字3バイト」＋「左記で扱えない文字を4バイト」で処理＋「絵文字を4バイト」で処理という感じですか？  
・絵文字が4バイトというのは何の仕様に基づいているのでしょうか？ UTF8？？
CC BY-SA 3.0
2017-10-15T14:29:07.663
38729
2017-10-18T04:02:33.557
2017-10-16T17:20:25.937
2238
7886
question
mysql 文字コード
utf8mb4は誰がどこで決めた仕様？
まずは Unicode 側の仕様  
Unicode
の世界では世界各地の「文字」を扱いますが、その文字１つ１つに抽象的な「文字コードポイント」を割り振っています。「文字」をファイルにセーブするとき、そのコードポイントをどのような「バイトの列」にするかを決めて取り扱うことになります。この、具体的な変換方法を「エンコーディング」と呼びます。この辺の話はあなた自身の質問  
[UTF-8で日本語1文字が3バイトなのはなぜ？](https://ja.stackoverflow.com/questions/38728/)  
にて述べられているわけです。

Unicode には BMP (Basic Multilingual Plane) という概念があって  
<https://ja.wikipedia.org/wiki/%E5%9F%BA%E6%9C%AC%E5%A4%9A%E8%A8%80%E8%AA%9E%E9%9D%A2>  
これは UNICODE 3.0 までで追加された「よく使うであろう」文字のセットのことで BMP にある文字は UTF-8 エンコーディングでは 3byte
となります。 BMP 外の文字は UTF-8 エンコーディングで 4byte となる仕様です。

日本語関連では「ひらがな」「かたかな」「よく使う漢字」は Unicode 1.1 で追加された関係でこの BMP の中に配置されています。そのため
UTF-8 エンコーディングで表記すると 3byte になります。「絵文字」などは Unicode 6.0 などで追加された関係で BMP
に入っていません。そのため「絵文字」を UTF-8 エンコーディング表記すると 4byte になります。

さてここからは [mysql](/questions/tagged/mysql "'mysql' のタグが付いた質問を表示") の仕様で  
<https://dev.mysql.com/doc/refman/5.6/ja/charset-unicode-utf8mb4.html>  
mysql のデーターベース文字エンコーディング utf8 は BMP
に登録されている文字だけを取り扱う代わりに、１文字３バイトのディスク空間を占有するという仕様です。非 BMP 文字は格納できないことになっています。

mysql のデーターベース文字エンコーディング utf8mb4 は BMP にない文字も取り扱えるようになったもので、非 BMP
文字は、１文字４バイトのディスク空間を占有するという仕様です。ただし utf8mb4 を使うアプリケーションソフトのほうにも非 BMP
文字を取り扱う機能が必要となります (特に UTF-16 を使っているアプリケーションはサロゲートペアに対応していなければならない) 。

いまどき的には常に utf8mb4 を採用しておけば間違いないでしょう。utf8 はサロゲートペアに非対応なアプリケーション専用と考えていいです。
CC BY-SA 3.0
2017-10-16T00:58:51.120
38738
2017-10-16T02:35:31.577
2017-10-16T02:35:31.577
8589
8589
38729
answer
全般的におかしいので指摘を残しておきます

> Unicode には BMP (Basic Multilingual Plane) という概念があって  
>
> <https://ja.wikipedia.org/wiki/%E5%9F%BA%E6%9C%AC%E5%A4%9A%E8%A8%80%E8%AA%9E%E9%9D%A2>  
>  これは UNICODE 3.0 までで追加された「よく使うであろう」文字のセットのことで

BMPは「文字のセット」ではありません。Basic Multilingual Planeという言葉の通り、面すなわち領域のことです。

BMPへの追加は今でも行われており、Unicode3.0までがBMP、それ以降が追加面、という区別の仕方は誤りです。

> BMP にある文字は UTF-8 エンコーディングでは 3byte となります。 BMP 外の文字は UTF-8 エンコーディングで 4byte
> となる仕様です。

BMPの領域の文字は3byteではなく1～3byteで表現されます。UTF-8は元々の仕様では31bitの領域を1～6byteで表現する可変長エンコーディングでしたが、Unicodeの拡張とISO10646の縮小により領域が21bitになったことで4byteまでの表現しか使われないことになりました。

> 日本語関連では「ひらがな」「かたかな」「よく使う漢字」は Unicode 1.1 で追加された関係でこの BMP の中に配置されています。そのため
> UTF-8 エンコーディングで表記すると 3byte になります。「絵文字」などは Unicode 6.0 などで追加された関係で BMP
> に入っていません。そのため「絵文字」を UTF-8 エンコーディング表記すると 4byte になります。

前述の通り、バージョンによりBMPか追加面かを区別するのは誤りです。現にUnicode
6.0で「絵文字」の一部はBMPにも追加されています。したがって、「絵文字」をUTF-8でエンコードしても必ずしも4byteになるとは限りません。

> さてここからは mysql の仕様で  
>  <https://dev.mysql.com/doc/refman/5.6/ja/charset-unicode-utf8mb4.html>  
>  mysql のデーターベース文字エンコーディング utf8 は BMP
> に登録されている文字だけを取り扱う代わりに、１文字３バイトのディスク空間を占有するという仕様です。非 BMP 文字は格納できないことになっています。
>
> mysql のデーターベース文字エンコーディング utf8mb4 は BMP にない文字も取り扱えるようになったもので、非 BMP
> 文字は、１文字４バイトのディスク空間を占有するという仕様です。

マニュアルに書かれている1文字3byteとか4byteというのは固定長文字列型を利用した場合の注意です。可変長エンコーディングを固定長領域に納めようとすると最大サイズを想定する必要があり、たいていの場合無駄が生じます。そのため、可変長文字列を使うように、ということがマニュアルに書かれているわけです。可変長文字列であれば、保存するのにUTF-8でエンコードしたバイト表現の長さ(とその長さの情報)しか必要としません。

> ただし utf8mb4 を使うアプリケーションソフトのほうにも非 BMP 文字を取り扱う機能が必要となります (特に UTF-16
> を使っているアプリケーションはサロゲートペアに対応していなければならない) 。

UTF-8は前述の通り元々可変長エンコーディングなので、「非BMP文字を取り扱う機能」は特別に必要はありません。問題になるのは、UTF-8のうち3byte表現までに対応を限定しているような場合です。

特別に対応が必要ないからこそ、絵文字の入力が通ってしまうがMySQLには正しく保存されない、とそういう問題が起きるわけです。

> いまどき的には常に utf8mb4 を採用しておけば間違いないでしょう。utf8 はサロゲートペアに非対応なアプリケーション専用と考えていいです。

サロゲートペアというのは(大雑把に言うと)UTF-16の話です。サロゲートペアに対応していない→アプリケーションが追加面を扱えない→utf8mb4を使う意味は無い、というのは正しいですが、追加面の取扱の可否とサロゲートペアのサポートの有無は1対1ではないので、おかしな表現です。
CC BY-SA 3.0
2017-10-17T07:38:49.233
38792
2017-10-18T04:02:33.557
2017-10-18T04:02:33.557
5793
5793
38729
answer