LoginSignup
6
3

More than 3 years have passed since last update.

innodb_large_prefixが有効になっている時は文字コードをutf8ではなくutf8mb4に設定する必要がある

Posted at

問題

データベースを作ろうとしたが実行されない。

ターミナル
naota7118@Naotas-MacBook-Air-6 my_syllabus % rails db:create
Configure a supported :charset and ensure innodb_large_prefix is enabled to support indexes on varchar(255) string columns.
Couldn't create 'mySyllabus_development' database. Please check your configuration.
rails aborted!
サポートされている:charsetを構成し、varchar(255)文字列のインデックスをサポートするためにinnodb_large_prefixが有効になっていることを確認します。
'mySyllabus_development'データベースを作成できませんでした。構成を確認してください。

解決方法

database.ymlにencodingとcharsetを下記のように設定したら解決し、無事データベースが作れた。

database.yml
default: &default
  adapter: mysql2
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  timeout: 5000
  #下記の2つを追加
  encoding: utf8mb4
  charset: utf8mb4

なぜ解決できたのか?

自分でも結果的にたまたま解決しただけではすっきりしないので、なぜ解決できたのか分かる範囲で書いておこう。

以前別のアプリケーションを作った時にMySQLの設置ファイルであるmy.cnfにinnodb_large_prefixを有効にする設定をしていた。
innodb_large_prefixは長い文字列を許可するための設定だ。

今回、encodingとcharsetの設定がそれに合う形に設定されていなかったのが原因だったようだ。
デフォルトのencodingとcharsetはutf8に設定されている。
これは1文字あたり3バイトまでしか許可されず、4バイトの文字は使えない設定だ。
4バイトの文字を許可するためにはutf8mb4を設定する必要がある。

鶏が先か卵が先かのような話だが、どうやら以前別のアプリを作った時に、絵文字も入力できるように文字コードをutf8mb4していた。
文字コードをutf8mb4に設定するために、innodb_large_prefixを有効にする設定が必要があり、この設定をしていたようだ。

今回解決した順番は逆だった。
innodb_large_prefixが有効になっているのに文字コードがutf8なのはおかしいぞというエラーだった。

参考:MySQL(InnoDB)でcharsetをutf8mb4にする注意点の現在

前提知識

database.ymlのencodingとcharsetは何を設定しているのか?

utf8は文字符号化方式の1つ。文字符号化方式は英語でcharacter encoding scheme。文字をコードに変換するルールの1つ。エンコード(encode)の意味は符号化。文字を符号(code)に変換すること。

前提として、人間の言葉とコンピュータの言葉は違う。日本人とアメリカ人の言葉が違うように。人間が使う言語は文字(例:"私はプログラミングを学ぶ")。コンピュータの言語は二進数(例:000101010011)。人間が使っている文字をコンピュータが処理できるような符号に置き換える、いわば通訳の役割をしている。

utf8とutf8mb4の違いは?

utf8は文字あたり最大3バイト使用しかできない。1文字あたり4バイト使う文字は使用できない。
utf-8mb4は4バイト使う文字も使用できる。
MySQLでデフォルトのuff-8の設定だと3バイトの文字しか使用できなかったのが、utf-8mb4を設定することで4バイトの文字も使用できるようになる。

MySQL公式リファレンスのutf8mb4文字セットの説明

innodb_large_prefixとは何か?

ターミナルに「innodb_large_prefixが有効」と表示されたが、innodb_large_prefixとは何なのか?
innodb_large_prefixはInnoDBオプションの1つ。

そもそもInnoDBとは何か?
MySQLのストレージエンジンのこと。ストレージエンジンとは、テーブル型(int型とかbigint型とか)に対するSQL操作をする部品のこと。

MySQL公式リファレンスのストレージエンジンの説明

innodb_large_prefixを有効にするとどういう状態になるのか?
MySQLリファレンスは下記のように説明している。

innodb_large_prefixを有効にすると、DYNAMICおよびCOMPRESSED行フォーマットを使用するInnoDB テーブルで、767バイトよりも長い (最大で 3072 バイトの) インデックスキープリフィクスが許可される。(このようなテーブルの作成には、innodb_file_format=barracuda および innodb_file_per_table=true のオプション値も必要になる。)

DYNAMICおよびCOMPRESSED行フォーマットが何なのかは一旦置いておいて、要は長い文字数でも許可される設定ということだ。

innodb_large_prefixはどのように設定するのか?

innodb_large_prefixはデフォルトではOFFになっているので、設定する場合は、my.cnfファイルにinnodb_large_prefix=1と記述して設定する必要があります。

コマンド行形式 --innodb-large-prefix
導入 5.6.3
システム変数 innodb_large_prefix
スコープ グローバル
動的 はい
ブール
デフォルト OFF

MySQL公式リファレンスのinnodb_large_prefixの説明

innodb_large_prefix=0 OFFに設定する場合
innodb_large_prefix=1 ONに設定する場合

ちなみに私のmy.cnfは現状こんな設定になっている。

/etc/my.cnf
[mysqld]
innodb_file_format=Barracuda
innodb_file_format_max=Barracuda
innodb_file_per_table=1
innodb_large_prefix=1
secure-file-priv = ""
sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
socket="/tmp/mysql.sock"

character_set_server=utf8mb4
collation_server=utf8mb4_unicode_ci

[mysqld_safe]
log-error=/var/log/mysqld.log

[client]
socket="/tmp/mysql.sock"

参考記事

MySQL(InnoDB)でcharsetをutf8mb4にする注意点の現在
MySQL公式リファレンスのinnodb_large_prefixの説明
MySQL公式リファレンスのutf8mb4文字セットの説明

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3