我正在考虑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多个字符是相同的(所有文本片段都很短,属于同一个一般主题)- 目标是对
text
列执行重复数据消除。对于这个特定的应用程序,这样做有望节省大量空间
将Text_id作为主键
当您开始遇到性能问题时,添加doc_id和text的索引并包含text_id。小心过早优化。
根据我的阅读,您需要将文档连接到文本。出于某种有趣的原因,这段文字可以复制。就我个人而言,我永远不会寻找重复的文本并为此进行优化,但人们很有趣,所以这里是:
-
创建一个仅包含文本的表对文本进行哈希(这样您可以获得更少的数据),并从中创建唯一索引。您的文本现在可以任意长。
-
插入到链接文档和文本的表中,通过外键链接它们。
祝贺您,您已经对某些内容进行了微优化。现在,如果你决定真的,真的压缩所有可能的空间,并对其进行超级优化,那么你可能会转向MySQL的存储引擎,与InnoDB相比,你会得到高达的空间减少12倍。
目标是什么?
- 是否要使用
text
来节省空间?似乎不太可能存到足够的钱 - "规格化"
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倍。