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

时间:2018-11-20 19:59:53

标签: mysql ruby-on-rails database

我试图理解一个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

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

references将供应商类型和供应商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_typesupplierssupplier_type

因此,我们拥有的是vendor_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

1 个答案:

答案 0 :(得分:0)

排序规则只是命令,真正的原因是字符集。 This answer显示了一些解决方法。像您一样完成索引限制也可以。

从255开始,很长时间以来(MySQL-4.0)varchar限制-其rather and arbitrary choice和基于数据的限制选择是最好的方法。

除了索引长度更大而长度更大时,涉及这些索引的联接有时还会使用MEMORY存储引擎,从而导致将varchar(X)转换为char(X),从而可以使用更多的内存。