Я пытаюсь понять ошибку MySQL, и она связана с некоторыми значениями по умолчанию, которые Rails генерирует с миграциями ActiveRecord. Учитывая это:
rails generate migration AddDetailsToProducts supplier:index:references{polymorphic}
class AddDetailsToProducts < ActiveRecord::Migration
def change
add_reference :products, :supplier, polymorphic: true, index: true, foreign_key: true
end
end
Так, что это делает? Во-первых, давайте посмотрим на полиморфизм. Polymorphic создаст столбцы поставщика VARCHAR (255) и столбца поставщика INT в продуктах. Я считаю, что VARCHAR установлен на 256 символов, так как ранние версии MySQL не поддерживали больше. Но помните, что столбцы VARCHAR в базе данных имеют переменную длину, поэтому в VARCHAR (255) по сравнению с VARCHAR (20) нет преимущества хранения в десятизначном значении.
При добавлении ссылки в качестве внешних ключей продуктов к первичному ключу поставщиков добавляются supplier_type и supplier_id. FOREIGN KEY - это поле (или набор полей) в одной таблице, которое ссылается на PRIMARY KEY в другой таблице. Это ключ, используемый для связи двух таблиц.
Так что я думаю, что add_reference делает что-то вроде этого:
CREATE TABLE products (
PRIMARY KEY (id),
FOREIGN KEY (supplier_id) REFERENCES suppliers(id)
FOREIGN KEY (supplier_type) REFERENCES suppliers(id)
)
CREATE INDEX 'index_suppliers_on_supplier_type' ON 'suppliers' ('supplier_type')
CREATE INDEX 'index_suppliers_on_supplier_id' ON 'suppliers' ('supplier_id')
Теперь я получил ошибку, как это:
Указанный ключ был слишком длинным; максимальная длина ключа составляет 767 байт: CREATE INDEX
index_suppliers_on_supplier_type
ONsuppliers
(supplier_type
)
Итак, у нас есть столбец supplier_type, который является VARCHAR (255), и мы попытались разместить на нем индекс. Я использую коалицию utf8_unicode_ci. Насколько я понимаю, это использует от 1 до 3 байтов на символ. Таким образом, даже если это будет использовать 3 байта для всех символов с максимум 256 символами, то есть 256 * 3 = 768. Один байт закончен. Это действительно не имеет смысла. Действительно ли решение состоит в том, чтобы просто добавить ограничение на максимальный размер символа для столбца? Я правильно понимаю?
Потому что, когда я делаю это, ошибка исчезает:
class ChangeSuppliers < ActiveRecord::Migration
def change
change_column :suppliers, :supplier_type, :string, limit: 191
end
end
Сопоставление - это просто порядок, настоящая причина - набор символов. Этот ответ показывает пару обходных путей. Индексный предел, как вы сделали это тоже работает.
Это был очень долгий срок (MySQL-4.0) с 255 года, какой предел varchar - скорее произвольный выбор, а выбор ограничения на основе ваших данных - лучший подход.
В дополнение к тому, что размеры индексов больше для больших длин, объединения, включающие их, иногда используют механизм хранения MEMORY, что приводит к преобразованию varchar (X) в char (X), который может использовать намного больше памяти.