簡體   English   中英

Rails 創建 schema_migrations - Mysql2::Error: Specified key was too long

[英]Rails creating schema_migrations - Mysql2::Error: Specified key was too long

我正在使用 Rails 3.2.6 和 Mysql 6.0.9(但我在 MySQL 5.2.25 上有完全相同的錯誤)

當我創建新數據庫 ( rake db:create ) 然后當我嘗試加載模式 ( rake schema:load ) 時,我收到此錯誤:

Mysql2::Error: Specified key was too long; max key length is 767 bytes: CREATE UNIQUE INDEX `unique_schema_migrations` ON `schema_migrations` (`version`)

經過數小時的研究,我找到了這些解決方案:

1. 將 MySQL 變量 innodb_large_prefix 更改為 true(或 ON)

這沒有用。 我在我的 Linux 服務器、我的 Mac 甚至 Windows 上都試過了——它就是行不通。

2. Monkeypatch ActiveRecord::SchemaMigration.create_table

我不需要version列的長度為 255(當它是 UTF-8 時,它需要 4*255 = 1020 字節,超過 MySQL 鍵的 767 字節限制)。 我也不需要它是 UTF-8,但數據庫中的所有其他表都是 UTF-8,並且我已將 utf8_czech_ci 設置為默認排序規則。

實際創建 schema_migrations 表的方法如下所示:

def self.create_table
  unless connection.table_exists?(table_name)
    connection.create_table(table_name, :id => false) do |t|
      t.column :version, :string, :null => false
    end
    connection.add_index table_name, :version, :unique => true, :name => index_name
  end
end

您可以在Github rails/rails上閱讀整個文件

所以我嘗試將:limit => 100添加到t.column語句中,但我也沒有成功使用此解決方案。 問題是當原始文件已經到位時,我無法加載此補丁程序。 換句話說——我的補丁在 ActiveRecord::SchemaMigration之前加載,所以它被覆蓋了。

當我把它放在config/initializers/patches/schema_migration.rb

require 'active_record/scoping/default'
require 'active_record/scoping/named'
require 'active_record/base'

module ActiveRecord
  class SchemaMigration < ActiveRecord::Base
    def self.create_table
      unless connection.table_exists?(table_name)
        connection.create_table(table_name, :id => false) do |t|
          t.column :version, :string, :null => false, :limit => 100
        end
        connection.add_index table_name, :version, :unique => true, :name => index_name
      end
    end
  end
end

它已成功加載,但在加載原始 ActiveRecord::SchemaMigration 時被覆蓋。

我試圖搞砸 ActiveSupport.on_load(:active_record) 但這似乎也不起作用。

有沒有辦法在原始 ActiveRecord::SchemaMigration 就位后加載此文件並使此補丁起作用?

你有什么建議嗎? 如果對您來說沒有意義,我可以澄清這個問題的任何部分。 問我吧。 我一直堅持這個太久了。

767 密鑰應該有效。 確保使用utf8編碼,而不是utf16 我有同樣的問題,我的錯誤是我不小心創建了utf16數據庫

我建議您刪除數據庫並按照以下說明重新創建一個新數據庫:

 mysql -u root -p -e "CREATE DATABASE {DB_NAME} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;"

我總是有這個錯誤,當它不是這個錯誤時:

Mysql2 ::錯誤:指定的密鑰太長; 最大密鑰長度為767字節:

就是這個:

Mysql2 ::錯誤:指定的密鑰太長; 最大密鑰長度為3072字節

所以我在這里建議我使用docker和官方mysql創建一個具有此設置的新數據庫

docker run -p 3306:3306 --name mysql-name -e MYSQL_ROOT_PASSWORD=name -d mysql:5.6 --innodb-large-prefix=1 --innodb-file-format=barracuda --innodb-file-per-table=1

這里重要的不是docker是數據庫啊配置

innodb-large-prefix = true innodb-file-format = barracuda innodb-file-per-table = true

最后這個database.yml如下改變utf8 latin1 sswedish是因為在服務器中我看到了:

development:
  host: 192.168.99.100
  database: name
  username: root
  password: root
  adapter: mysql2
  charset: latin1
  encoding: latin1
  collation: latin1_swedish_ci


test:
  host: 192.168.99.100
  database: name_test
  username: root
  password: root
  adapter: mysql2
  charset: latin1
  encoding: latin1
  collation: latin1_swedish_ci

production:
  host: 192.168.99.100
  database: name
  username: root
  password: root
  adapter: mysql2
  charset: latin1
  encoding: latin1
  collation: latin1_swedish_ci

之后工作

bundle exec rake db:create
bundle exec rake db:migrate

我用猴子補丁做了這個,沒有在這里建議的猴子補丁,它的工作原理

config/initializers/ar_innodb_row_format.rb

ActiveSupport.on_load :active_record do
  module ActiveRecord::ConnectionAdapters   
    class AbstractMysqlAdapter 
      def create_table_with_innodb_row_format(table_name, options = {}) 
        table_options = options.reverse_merge(:options => 'ENGINE=InnoDB ROW_FORMAT=DYNAMIC')

        create_table_without_innodb_row_format(table_name, table_options) do |td|
         yield td if block_given? 
        end
      end
      alias_method_chain :create_table, :innodb_row_format 
    end
  end
end

我對長度為 2000 的 varchar 的名為 version 的列有同樣的問題

class AddVersionToUsers < ActiveRecord::Migration
  def change
    add_column :users, :version, :string, limit:2000
    add_index  :users, :version
  end
end

我使用的是 latin 1 1 character 1 byte,但現在我想使用 utf8mb4 1 character 4 bytes。

像這樣配置你的數據庫你可以獲得直到 3072 字節的索引:

docker run -p 3309:3306 --name test-mariadb -e MYSQL_ROOT_PASSWORD=Cal1mero. -d mariadb:10.2 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --innodb-large-prefix=1 --innodb-file-format=barracuda --innodb-file-per-table=1 --innodb-strict-mode=1 --innodb-default-row-format=dynamic

這對於 latin_1 來說足夠了(將是 2000 字節),但對於 utf8mb4 它將是 8000 字節。 在這個鍵中你有一些選擇

添加一個名為 hash_version 的列並在該列上實現索引。

Consistent String#hash 僅基於字符串的內容

縮短字符串,它應該可以工作,但取決於您的需要

或在您的遷移中使用全文,如下所示:

class AddVersionToUsers < ActiveRecord::Migration
  def change
    add_column :users, :version, :string, limit:2000
    add_index  :users, :version, type: :fulltext
  end
end

參考:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM