【问题标题】:MySQL UNIQUE KEY design: compound INT + VARCHAR key vs. single-col VARCHAR keyMySQL UNIQUE KEY 设计:复合 INT + VARCHAR 键与单列 VARCHAR 键
【发布时间】:2015-04-29 19:49:27
【问题描述】:

我正在考虑 MySQL 5.6 InnoDB 表的以下模式。我无法决定使用哪些键:

    "CREATE TABLE IF NOT EXISTS `context` ("
    "  `text_id` INT NOT NULL AUTO_INCREMENT,"
    "  `doc_id` INT NOT NULL,"
    "  `text` VARCHAR(255),"
    "  PRIMARY KEY (`text_id`),"
    "  UNIQUE KEY `text_uk` (`text`),"                  <<< OPTION 1
    "  UNIQUE KEY `docidtext_uk` (`doc_id`, `text`),"   <<< OPTION 2
    ") ENGINE=InnoDB "

我可以要求列 text 是唯一的(选项 1),或者我可以允许 text 中的一些重复条目,而是在 doc_id + text 上放置一个复合唯一键(选项2)。从存储的角度来看,选项 1 显然更有效,但查询速度对我们来说是更重要的问题。

鉴于text 很长,因此生成的唯一键效率低下,我怀疑使用复合键可能会导致更快的查询(注意doc_id 是一个整数,因此相对非常有效)。但是,我对 MySQL 内部结构不够熟悉,无法理解复合键是否以这种方式工作。

如果读取速度是我们最关心的问题,那么哪些选项是最佳做法?保留两把钥匙有什么害处或好处吗?

注意事项:

  • 查询此表的唯一函数始终可以访问doc_idtext 的值(此函数的唯一目的是查找text_id)。
  • 该表目前没有数据,但我们预计它最终将包含大约 10 亿行。
  • 每个doc_iddoc_id 列的其他行中最多有99 个重复项。
  • text 列中可能有数百万个单元格的前 20 多个字符是相同的(所有文本 sn-ps 都很短且属于同一个主题)。
  • 目标是对text 列进行重复数据删除。对于这个特定的应用程序,这样做有望节省大量空间。

【问题讨论】:

  • 索引使用 B 树。效率取决于您拥有具有长且公共值前缀的行的频率。
  • 您还需要考虑应用程序。如果两个人编写的文档恰好具有相同的text 怎么办?将其设为唯一列将不允许这样做。顺便说一句,255 个字符并不是很长。
  • 巴尔玛,感谢您的回复。如果我们将唯一键单独放在text 列上,这两个文档(可能还有更多)将共享相同的text_id。在这种情况下,表中将省略 doc_id 列。
  • 一个 255 字符的索引通常不会引起我的注意,但这是一个大表 - 十亿行 - 而且只有几个重复的 doc_ids。
  • 正如我上面所说,列的完整大小不是问题。重要的是有多少值有共同的长前缀。如果通常可以在前 10-20 个字符中区分它们,那么它实际上与 20 个字符的列上的索引相同。

标签: mysql innodb unique-key unique-index compound-key


【解决方案1】:

将 Text_id 作为主键。
在 doc_id 和 text 上添加索引,并在您开始遇到性能问题时包含 text_id。小心过早的优化。

【讨论】:

    【解决方案2】:

    根据我阅读的内容,您需要将文档连接到文本。由于某些有趣的原因,该文本可以被复制。就个人而言,我永远不会寻找重复的文本并为此进行优化,但人们很有趣,所以这里是:

    • 创建一个仅包含文本的表格。 散列文本(这样你得到的数据更少)并从中创建唯一索引。您的文本现在可以任意长了。

    • 插入链接文档和文本的表格中,通过外键链接它们。

    恭喜,您已经对某些内容进行了微优化。现在,如果您决定真正、真正地压缩所有可能的空间并超级优化东西,那么您可能会求助于this storage engine for MySQL,与InnoDB。

    【讨论】:

      【解决方案3】:

      目标是什么?

      • 重复数据删除text 以节省空间?似乎不太可能节省足够的钱。
      • 'Normalize'text 这样如果你需要改变一个字符串,你可以在一个地方改变它吗?没有任何暗示。
      • 发现哪个doc 包含给定的text?显然不需要。
      • 节省其他几个表中的空间,否则这些表中会包含text?显然只有另一张桌子。

      结论:由于您似乎不需要任何东西来证明这张表的合理性,所以

      亲吻。

      只需将text 放在需要它的表中即可。如果我在 4 个要点之一上错了,我会更改答案。

      编辑

      如果会有很多重复的字符串,并且目标是去重,我推荐

      CREATE TABLE context (
          text_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
          text VARCHAR(255) NOT NULL,
          PRIMARY KEY(text_id),
          UNIQUE(text)            -- for finding dup
      ) ENGINE=InnoDB;            -- because of the way it clusters
      
      INSERT INTO context (text) VALUE ('$escaped_text')
          ON DUPLICATE KEY UPDATE text_id = LAST_INSERT_ID(text_id);  -- see ref manual
      $text_id = LAST_INSERT_ID();
      

      如果字符串往往很长,请改用 VARBINARY,并在客户端中压缩/解压缩。对于典型文本,压缩会将文本缩小 3 倍。

      【讨论】:

      • 目标是text的重复数据删除。对于这个特定的应用程序,是的,预计会节省大量空间。
      • 添加了“去重”推荐
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 2013-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多