假设我有一个包含长变量(URL,例如 100-250 个字符)的大表(超过 100000 个条目)。将 MD5 散列作为旁边的单独字段以从表中获取单行是否对提高性能有意义?
SELECT * FROM `urls` WHERE `url` = 'http://long-phrase...' LIMIT 1;
或
SELECT * FROM `urls` WHERE `url_md5` = MD5('http://long-phrase...') LIMIT 1;
最佳答案
我想使用 INDEX 就足够了,这就是为什么,在下雪的星期天以平淡无奇的心情写的:
数据库将其行存储在文件中,一个接一个:
id url name descr visited
1 http://... somewhere i like it 2013-01-01
2 http://... wherever i dislike it 2013-01-02
...
磁盘上的数据大致如下:
[s:35:http://...s:9:somewhere...][s:45:http://...s:9:wherever...][...]
一堆字节,很多。如果您要求数据库搜索给定的术语,数据库必须通过扫描文件来扫描“行”并应用搜索术语。假设您有 100 万行,数据库必须扫描 100 万行。假设您要在行中搜索“url”字段。假设您缩短(或扩展,执行“http://goo.gl/P0Gwz”的 md5)字符串后“搜索”变得更容易:您仍然需要搜索 100 万行。
另一方面,如果您只能搜索有序的行列表,那将是 really speed things up .因此,假设数据库现在存储的行不是按您插入行时排序的,而是按“url”字段排序的。现在,一旦您插入新行,数据库就必须重新排序磁盘上所有存储的字节。当然,您现在可以更快地搜索,但 INSERT 操作要慢得多。并且不要忘记:明天您要搜索“descr”字段。现在怎么办?重新排序整个文件?保留文件的 2 个副本?
更好的方法是使用寄存器,这是一个有序列表,其中包含查找“行”的位置的引用。这个想法与现实世界的图书馆一样古老:只需将书籍一个接一个地放在书架上,编号,然后创建列表:一个按作者姓名排序,一个按出版年份排序,一个按标题排序等等。任何给定的人想要搜索作者选择作者注册,通过类似于二进制搜索的方法扫描名称(如果这个人很聪明),获取书的编号,去书架并快速拿起书.
那个“寄存器”东西也称为“索引”:对磁盘上引用行位置的有序引用列表:
[s:35:http://...s:9:somewhere...][s:45:http://...s:9:wherever...][...]
^ ^ ^
| | |
| | |
i1 -------------------------------- ^ |
i2 ------------------------------------------------------------------>
i3 -^ |
i100 -------------------------------------------------------------^
例如,您现在可以检查 i50
以查看您的搜索词是否匹配。如果索引函数指向大于 50 的值,则在下一轮检查 i75,如果小于 50,则检查 i25,依此类推。
给你数字:给定 100 万行,你搜索你必须扫描的“url”字段:
- 在最坏的情况下需要 100 万行才能找到您的 url(“它不在此处”)。
- 平均 50 万行(“平均分配”)。
- log2(10^6) == 20 在最坏的情况下检查 INDEX 中的 url。
- log2(10^6)-1 == 19 平均检查 INDEX 中的 url。
明天你将有 200 万行。现在您必须通过不使用 INDEX 扫描超过 200 万行,并且您将不得不扫描最多 20 次才能找到正确的记录或什么也找不到。数百万次字符串比较与 20 次比较。您会看到使用 INDEX 的影响有多大。
在此处阅读有关该主题的更多信息:
关于php - 选择使用长变量与 MD5 性能明智,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14402763/