我有一个包含以下内容的MySQL表:
CREATE TABLE `url_list` (
`id` int(10) unsigned NOT NULL auto_increment,
`crc32` int(10) unsigned NOT NULL,
`url` varchar(512) NOT NULL,
PRIMARY KEY (`id`),
KEY `crc32` (`crc32`)
);
当将数据插入相关表时,我需要从该表中查找主键,并且使用crc32确实加快了速度,同时允许一个小索引。 URL确实需要是唯一的,但我想避免使用比实际数据更多的索引。
如果该值不存在,我需要插入它,但使用INSERT IGNORE
或ON DUPLICATE KEY
等结构要么我要在巨大的varchar上放一个唯一的,或者不要利用我的索引。
如何“SELECT id else INSERT”,同时保留表中已有80-90%命中的查找速度?
答案 0 :(得分:3)
我建议放弃id
列和crc32
,因为它们不是必需的。
您可以使用MD5()
哈希来提供从冗长的URL数据计算的固定长度,几乎唯一的值,然后将该哈希用作主键。
CREATE TABLE `url_list` (
`url_hash` BINARY(16) NOT NULL PRIMARY KEY
`url` VARCHAR(512) NOT NULL
);
DELIM !!
CREATE TRIGGER `url_ins` BEFORE INSERT ON `url_list`
FOR EACH ROW
BEGIN
SET NEW.`url_hash` = UNHEX( MD5( NEW.`url` ) );
END!!
然后您可以使用INSERT..ON DUPLICATE KEY UPDATE
,因为与crc32
不同,哈希的碰撞几率非常低。
修改:请参阅http://en.wikipedia.org/wiki/Birthday_attack。如果您在2000年内每天记录100万个不同的URL,则这些URL的MD5哈希值仍然不太可能包含冲突,而不是硬盘具有无法纠正的位错误。
答案 1 :(得分:1)
This website为类似问题提供了解决方案。