在WHERE中使用MD5(URL)代替DB中的URL

时间:2009-09-08 17:00:58

标签: sql mysql performance innodb

我有一个很大的MySQL InnoDB表(大约1百万条记录,每周增加300K)让我们说博客文章。该表有一个带索引的url字段。

通过在其中添加新记录,我正在检查具有相同网址的现有记录。以下是查询的外观:

SELECT COUNT(*) FROM `tablename` WHERE url='http://www.google.com/';

目前,系统每秒产生大约10-20个查询,这个数量将会增加。我正在考虑通过添加附加字段来提高性能,该字段是URL的MD5哈希值。

SELECT COUNT(*) FROM `tablename` WHERE md5url=MD5('http://www.google.com/');

所以它会更短,并且长度恒定,与URL字段相比,索引更好。你们怎么看?它有意义吗?

我的朋友的另一个建议是使用CRC32而不是MD5,但我不确定CRC32的结果有多独特。让我知道你对CRC32这个角色的看法。

更新:URL列对于每一行都是唯一的。

7 个答案:

答案 0 :(得分:4)

在URL上创建非聚集索引。这将让您的SQL引擎在内部完成所有优化,并将产生最佳结果!

如果在VARCHAR列上创建索引,SQL无论如何都会在内部创建一个哈希,并且使用索引可以提供一个数量级甚至更多的更好的性能!

另外,如果您只检查URL是否存在,请记住,某些SQL产品会通过如下查询生成更快的结果:

IF NOT EXISTS(SELECT * FROM `tablename` WHERE url='')
    -- return TRUE or do your logic here

答案 1 :(得分:0)

我认为CRC32实际上对这个角色更好,因为它更短,并且节省了更多的SQL空间。如果你收到那么多查询,那么对象是为了节省空间吗?如果它完成了这项工作,我会说去吧。

虽然它只有32位,而且长度较短,但它并不像MD5那么独特。您必须决定是否需要唯一,或者如果您想节省空间。

我仍然认为我会选择CRC32。

  

我的系统每秒产生大约4k个查询,我使用CRC32作为链接。

答案 2 :(得分:0)

使用内置索引总是最好的,或者你应该自愿添加到他们的代码库中;)

使用哈希时,在哈希和URL上创建一个2列索引。如果您只选择索引上的前几个字母,它仍然会完全匹配,但它的索引不会超过前几个字母。

这样的事情:

INDEX(CRC32_col, URL_col(5))

在这种情况下,任何一个哈希都可以工作。这是空间与速度的权衡。

此外,此查询会更快:

SELECT * FROM table WHERE hash_col = 'hashvalue' AND url_col = 'urlvalue' LIMIT 1;

这将找到第一个值并停止。比COUNT(*)计算找到许多匹配要快得多。

最终,最好的选择是为每个变体和基准制作测试用例。

答案 3 :(得分:0)

大多数SQL引擎是否在内部使用哈希函数进行文本列搜索?

答案 4 :(得分:0)

如果您要使用散列键并且关注冲突,请使用两个不同的散列函数并连接两个散列值。

但即使你这样做,也应该始终将原始键值存储在行中。

答案 5 :(得分:-1)

如果选择语句的结果倾向于相当高,则另一种解决方案是使用单独的表来跟踪计数。显然使用该技术会有很高的惩罚,但如果这个特定的查询是常见的并且速度太慢,这可能是一个解决方案。

此解决方案中存在明显的权衡,您可能不希望在每次插入新记录后更新此第2个表,因为这会降低您的插入速度。

答案 6 :(得分:-1)

如果选择哈希,则需要考虑碰撞。即使使用像MD5这样的大型哈希,您也必须考虑meet-in-the-middle概率,更好地称为birthday attack。对于像CRC-32这样的较小的哈希,冲突概率会非常大,而你的WHERE必须指定哈希完整的URL。

但我要问,这是花费你努力的最佳方式吗?还有什么可以优化吗?除非您有明确的指标和测量结果表明此问题 是系统的瓶颈,否则您可能正在进行过早优化。毕竟,这种搜索是针对(所有这些)数据库进行优化的,并且通过执行类似哈希的操作,实际上可能会降低性能(例如,您的索引可能会变得支离破碎,因为哈希的分布与URL不同)。 / p>