我有一个很大的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列对于每一行都是唯一的。
答案 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>