【问题标题】:Primary key cannot hold more than 767 or 1000 character as primary key主键不能包含超过 767 或 1000 个字符作为主键
【发布时间】:2021-05-11 08:27:49
【问题描述】:

我正在尝试创建一个表,其中一个列将包含超过 5000 个字符的字符,并且我不希望此列的任何行重复,因此我使用主键来创建此列中的每一行已存在时不再保存

但问题是当我尝试使用 column_name VARCHAR(5500) Primary key 创建此列时,它给了我这个错误 Specified key was too long; max key length is 767 bytes

我搜索了很多,发现 InnoDB 引擎只接受 767 个字符作为最大长度,而 MYISAM 引擎接受 1000 个字符,但这对我没有帮助,因为此列可能包含超过 5000 个字符

我正在寻找的是一种创建列的方法,该列的任何行都不能重复并接受许多字符

CREATE TABLE data_table (
    date_time VARCHAR(100),
    message VARCHAR(5500) PRIMARY KEY
) ENGINE = MYISAM CHARACTER SET latin1

【问题讨论】:

  • 似乎没有意义,您只需更改 1 个字符就不会被视为重复。
  • 你能给我一些更有效的解决方案吗?
  • 先运行select?您不能索引 5000 个字符。
  • 我发现 Memory 引擎可以容纳 3072 个字符作为最大长度也许它可以工作,尽管我希望找到可以容纳更多的引擎或者如果没有限制 ????
  • 另一个线程建议存储哈希。在这种情况下,您只需要担心哈希冲突。如果您的应用可以接受这种可能性。

标签: mysql indexing duplicates unique-constraint


【解决方案1】:

你已经达到了一个基本的限制。可悲的是,只要您需要,再多的谈判或黑客攻击都不会找到一种方法来制作索引。因此,唯一索引并不能解决您防止重复文本字符串的问题。

许多人将hash of long text fields 与文本一起存储。

SHA-256 is a decent choice for a hash。哈希的问题是哈希冲突的可能性。也就是说,两个不同的文本字符串可能会生成完全相同的哈希值。使用 SHA-256 或更大的哈希值,that chance is very low indeed。

如果您使用 SHA-256,则需要这样定义的列。 (当然,32 字节与 256 位相同。)

text_hash BINARY(32)

然后当你去插入文本时你可以这样做。

INSERT INTO tbl (text, text_hash) VALUES(?, UNHEX(SHA2(?, 256));

如果您将text_hash 设置为唯一索引,您将有办法通过在尝试时抛出错误来防止重复。像这样的。

 CREATE UNIQUE INDEX no_text_dups_please ON tbl(text_hash);

【讨论】:

    【解决方案2】:

    需求:“[one] 列将包含字符(超过 5000 个字符),我不希望此列的任何行重复”

    PRIMARY KEY 在指定的字段上添加 UNIQUE CONSTRAINT,但如果您不需要将其用作 PRIMARY KEY,请仅使用 UNIQUE。此外,我不建议在大文本列上使用 UNIQUE CONSTRAINT。

    我建议您通过制作和存储文本的哈希值来检查数据的唯一性。

    【讨论】:

      【解决方案3】:

      当然,哈希是一种方式。 (我认为最新的 MariaDB 有一种神奇的技术!)这是另一种方法:

      出于多种原因,您应该从 MyISAM 切换到 InnoDB,但在本次问答中我将忽略这一点。

      CREATE TABLE data_table (
          date_time VARCHAR(100),
          message VARCHAR(5500) PRIMARY KEY
          INDEX(message(100))
      ) CHARACTER SET utf8mb4   -- since you might get non-English test, including Emoji.
      

      (“100”是速度和空间之间的权衡。)

      但是你必须做一个额外的测试:

      SELECT 1 FROM data_table WHERE message = ?
      

      如果你拿回了一些东西,你就有一个重复——采取行动。否则执行 INSERT。

      糟糕,我确实需要坚持使用 InnoDB —— 至少在插入相同消息时可能存在冲突连接:

      BEGIN;
      SELECT 1 FROM data_table WHERE message = ? FOR UPDATE;
      if ... then handle dup and don't COMMIT
      INSERT INT data_table (date_time, message) VALUES (?, ?);
      COMMIT;
      

      您可能希望将所有内容隐藏在存储过程中。

      【讨论】:

        猜你喜欢
        • 2012-06-29
        • 2018-09-19
        • 2011-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多