使用coalation utf8_unicode_ci限制索引列的VARCHAR长度的必要性



我试图理解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将在产品中创建一个supplier_type VARCHAR(255(和supplier_id INT列。我相信VARCHAR设置为256个字符,因为MySQL的早期版本不支持更多字符。但请记住,数据库中的VARCHAR列是可变长度的,因此VARCHAR(255(中的10个字符值与VARCHAR的(20(相比没有存储优势。

references将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 INDEXsuppliers(supplier_type(上的index_suppliers_on_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

排序规则只是顺序,真正的原因是字符集。这个答案显示了几个解决方法。像你这样的指数限制也是有效的。

自从255以来,已经有很长一段时间了(MySQL-4.0(什么是varchar限制——它是一个相当随意的选择,根据您的数据选择限制是最好的方法。

除了索引大小越大,长度越大,涉及这些的联接有时会使用MEMORY存储引擎,导致varchar(X(被转换为char(X(,这可能会使用更多的内存。

最新更新