1

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

通过在其中添加新记录,我正在检查具有相同 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 列都是唯一的。

4

7 回答 7

4

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

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

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

IF NOT EXISTS(SELECT * FROM `tablename` WHERE url='')
    -- return TRUE or do your logic here
于 2009-09-08T17:08:03.020 回答
0

我认为 CRC32 实际上更适合这个角色,因为它更短并且节省了更多的 SQL 空间。如果您收到这么多查询,那么目的是为了节省空间吗?如果它做的工作,我会说去吧。

虽然,由于它只有 32 位,而且长度更短,但它当然不像 MD5 那样独特。您必须决定是否要独特,或者是否要节省空间。

我仍然认为我会选择 CRC32。

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

于 2009-09-08T17:03:07.757 回答
0

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

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

像这样的东西:

INDEX(CRC32_col, URL_col(5))

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

此外,此查询将更快:

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

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

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

于 2009-09-08T17:17:43.093 回答
0

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

于 2009-09-09T02:05:04.203 回答
0

如果您要使用散列键并且担心冲突,请使用两个不同的散列函数并将两个散列值连接起来。

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

于 2009-09-09T02:59:13.593 回答
-1

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

此解决方案涉及明显的权衡,您可能不想在每次插入新记录后更新第二个表,因为这会减慢您的插入速度。

于 2009-09-08T17:08:21.897 回答
-1

如果选择散列,则需要考虑碰撞。即使使用像 MD5 这样的大散列,您也必须考虑中间相遇概率,即更为人所知的生日攻击。对于像 CRC-32 这样的较小散列,冲突概率将非常大,您的 WHERE 必须指定散列完整 URL。

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

于 2009-09-08T17:24:51.520 回答