【发布时间】: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_id和text的值(此函数的唯一目的是查找text_id)。 - 该表目前没有数据,但我们预计它最终将包含大约 10 亿行。
- 每个
doc_id在doc_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