2015-09-08 10 views
5

Ich versuche, die folgende Migration zu tun:Ecto die Schaffung eindeutiger Index ist fehlgeschlagen für Mysql/MariaDB

defmodule Shopper.Repo.Migrations.MakeNameUniqueShopper do 
    use Ecto.Migration 

    def change do 
    create unique_index :shoppers, [:name] 
    end 
end 

versuchte auch create unique_index :shoppers, [:name], name: :name_unique, create unique_index :shoppers, [:name], name: "name_unique" und create index(:shoppers, [:name], unique: true)

Aber sie scheiterten mit ähnlichen Fehler:

[info] == Running Shopper.Repo.Migrations.MakeNameUniqueShopper.change/0 forward 

[info] create index shoppers_name_index 
** (Mariaex.Error) (1071): Specified key was too long; max key length is 767 bytes 
    (ecto) lib/ecto/adapters/sql.ex:172: Ecto.Adapters.SQL.query!/5 
    (elixir) lib/enum.ex:1261: Enum."-reduce/3-lists^foldl/2-0-"/3 
... 
... 

Jede Hilfe wäre sehr geschätzt, um mir mit dem Fehler zu helfen.

Hinweis: Ich verwende ecto 1.02

Es folgt die erste Migration erstellt mit mix phoenix.gen.model

defmodule Shopper.Repo.Migrations.CreateV1.Shopper do 
    use Ecto.Migration 

    def change do 
    create table(:shoppers) do 
     add :name, :string 
     add :oauth_token, :string 

     timestamps 
    end 
    end 
end 

Info: das name Feld utf8mb4 ist, spezifiziert durch mein Schema

Update: Ich weiß, die Lösung ist diezu reduzierenFeldlänge, aber wie funktioniert es mit Phoenix-Modell und Migration? Wie es eine Schnur erwartet?

+1

Bitte stellen Sie 'SHOW CREATE TABLE' bereit, damit wir die Besonderheiten besprechen können. –

+0

@RickJames Ich bin mir nicht sicher, ob es hier relevant ist. Es ist erstellt von 'Mix phoenix.gen.model' – ardhitama

+0

Wie können wir die Felder, die es im Schlüssel verwendet, ohne die Struktur der Tabelle zu sehen? Darum bittet @RickJames (wenn ich das richtig verstehe). –

Antwort

1

Danke an José Valim für die Hilfe bei seiner Antwort, obwohl diese Antwort die genaue Lösung für mein Problem ist.

Erstellen Sie ein neues ecto Migrationsskript mit dem folgenden Code:

defmodule Shopper.Repo.Migrations.MakeNameUniqueShopper do 
    use Ecto.Migration 

    def change do 
    alter table(:shoppers) do 
     modify :name, :string, size: 100 
    end 

    create unique_index :shoppers, [:name], name: :shopper_name_unique 
    end 
end 
3

Das Feld "Name" ist zu lang. Sie sollten entweder sicherzustellen, dass es eine Größe von weniger als 767 Bytes hat, indem die Größe Option vorbei, wenn es oder Index nur einen Teil des Feldes erklärt:

create unique_index :shoppers, ["name(20)"], name: :shoppers_name_unique 

Beachten Sie, dass Sie die gleichen Namen geben müssen, wenn unique_constraint/2 Aufruf in dein Änderungsset

+0

Ich verpasste einen Punkt über ein Feld sollte weniger als 767 Bytes, die eine Zeichenfolge in 'add: name,: string' ist eigentlich' varchar (255) '. Aber '[" name (20) "]' ist kein korrekter Feldname, also führe zu einem anderen Fehler – ardhitama

+0

Ich denke, die richtige Antwort wäre es zuerst zu 'name (20)' dann 'create unique_index: shoppers, [: name], name:: shopper_name_unique' – ardhitama

+0

und ... mein Schema ist utf8mb4 – ardhitama

0

Eine alternative kürzere varchar/Textspalte Größen mit utf8mb4 Codierung schaffen, ist MySQL zu konfigurieren, dass die maximale InnoDB Indexpräfixes Größe zu 3072 Bytes zu erhöhen .

defmodule Shopper.Repo.Migrations.CreateV1.Shopper do 
    use Ecto.Migration 

    def change do 
    # just needs to be done once 
    execute "SET GLOBAL innodb_file_format = BARRACUDA" 
    execute "SET GLOBAL innodb_file_per_table = ON" 
    execute "SET GLOBAL innodb_large_prefix = ON" 

    # in MySQL 5.7.9 or higher, this sets the default row format 
    # otherwise for all new tables you create, you must manually 
    # alter row_format to dynamic before adding any string/text columns 
    execute "SET GLOBAL innodb_default_row_format = DYNAMIC" 

    # change existing shoppers row format to dynamic 
    execute "ALTER TABLE shoppers ROW_FORMAT = DYNAMIC" 

    create unique_index :shoppers, [:name], name: :shopper_name_unique   
    end 
end 
0

das Problem hier ist der Schlüssel Größe des InnoDB (767 Bytes), die direkt abbildet auf die mögliche Größe von varchar() Spalten in Bezug auf die charset der Spalte. Wenn Sie den Zeichensatz utf8 verwenden, kann eine varchar Spalte 255 Zeichen bei max. Wenn Sie utf8mb4 verwenden, kann eine Spalte varchar nur 191 Zeichen speichern.

dieses Blog-Post geht in Einzelheiten: https://mathiasbynens.be/notes/mysql-utf8mb4

während der Anwendung dieser Regel auf den Index, wie josé schlägt sicherlich eine Möglichkeit ist, würde ich sagen, Sie besser Ihre varchar Spalte Größen fix und haben CREATE INDEX nicht beschweren an erster Stelle und haben ein richtiges Tabelle Spaltenlayout:

defmodule Shopper.Repo.Migrations.CreateV1.Shopper do 
    use Ecto.Migration 

    def change do 
    create table(:shoppers) do 
     add :name, :varchar, size: 191 
     add :oauth_token, :varchar, size: 191 

     timestamps 
    end 
    create unique_index(:shoppers, [:name]) 
    end 
end 

attention: add :name, :string, size: 191 will not work as ecto maps the :string type directly to varchar(255) in the mysql adapter

meine Meinung nach mysql-Adapter ist das ecto, nehmen die charset in Betracht, wenn :string zu seiner nativen Typzuordnung just like rails does it.

Verwandte Themen