alembic でインデックスが 767 バイト以上の対策
MySQL5.6 で alembic を使った場合に、
"Warning: Specified key was too long; max key length is 767 bytes" が出る場合の対策メモ。
$ alembic upgrade head INFO [alembic.migration] Context impl MySQLImpl. INFO [alembic.migration] Will assume non-transactional DDL. INFO [alembic.migration] Running upgrade -> 202b6777d6c, Create init table. /opt/python3.4/site-packages/pymysql /cursors.py:134: Warning: Specified key was too long; max key length is 767 byte s result = self._query(query)
原因は以下を参照。
MySQL(InnoDB) で "Index column size too large. The maximum column size is 767 bytes." いわれるときの対策 - かみぽわーる
ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes - sonots:blog
my.cnf で innodb の設定を変える。
MySQL の設定だけを変えて、alembic を実行してもエラーになる。
INFO [alembic.migration] Context impl MySQLImpl. INFO [alembic.migration] Will assume non-transactional DDL. INFO [alembic.migration] Running upgrade -> 202b6777d6c, Create init table. Traceback (most recent call last): File "/opt/virtualenvs/pisces/bin/alembic", line 9, in <module> .... sqlalchemy.exc.InternalError: (pymysql.err.InternalError) (1709, 'Index column s ize too large. The maximum column size is 767 bytes.') [SQL: 'CREATE INDEX ix_co ntacts_email ON contacts (email)']
マイグレーションようのスクリプトにも手を入れてやる必要がある。
"""Create init table. Revision ID: 202b6777d6c Revises: None Create Date: 2014-10-11 18:23:14.081574 """ # revision identifiers, used by Alembic. revision = 'xxxxx' down_revision = None import os import simplejson as json from alembic import op import sqlalchemy as sa from sqlalchemy.sql import table, column from sqlalchemy.dialects.mysql import INTEGER as Integer def upgrade(): op.create_table( 'users', sa.Column('id', sa.Integer, primary_key=True), sa.Column('name', sa.Unicode(50), nullable=False, index=True), sa.Column('password', sa.String(128), nullable=False, index=True), sa.Column('email', sa.String(254), nullable=False, index=True), sa.Column('created_at', sa.DateTime), sa.Column('updated_at', sa.DateTime), mysql_row_format='DYNAMIC' ) def downgrade(): op.drop_table('users')
こんな感じで `create_table()` で mysql_xxx という形で MySQL 特有のオプションを渡す。
これで実行すると、エラーなく完了する。
$ alembic upgrade head INFO [alembic.migration] Context impl MySQLImpl. INFO [alembic.migration] Will assume non-transactional DDL. INFO [alembic.migration] Running upgrade -> xxxxx, Create init table.