首页 > 解决方案 > 使用联合 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

那么这有什么作用呢?首先,让我们看一下多态性。多态将在产品中创建供应商类型 VARCHAR(255) 和供应商 ID INT 列。我相信 VARCHAR 设置为 256 个字符,因为 MySQL 的早期版本不支持更多字符。但请记住,数据库中的 VARCHAR 列是可变长度的,因此 VARCHAR(255) 中的十个字符值与 VARCHAR(20) 相比没有存储优势。

引用将供应商类型和供应商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 ON suppliers( supplier_type)

所以我们有一个供应商类型列,它是 VARCHAR(255),我们试图在它上面放置一个索引。我正在使用 utf8_unicode_ci 联合。我的理解是每个字符使用 1 到 3 个字节。因此,即使这是对最多 256 个字符的所有字符使用 3 个字节,也就是 256 * 3 = 768。超过一个字节。这真的没有意义。解决方案真的只是为列的最大字符大小添加限制吗?我是否正确理解这一点?

因为当我这样做时,错误消失了:

class ChangeSuppliers < ActiveRecord::Migration
  def change
    change_column :suppliers, :supplier_type, :string, limit: 191
  end
end

标签: mysqlruby-on-railsdatabase

解决方案


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

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

除了索引大小对于更大的长度更大之外,涉及这些的连接有时会使用 MEMORY 存储引擎导致 varchar(X) 被转换为可以使用更多内存的 char(X)。


推荐阅读