索引还是唯一键?MySql中哪个更好?

17

我有一个问题。

假设你有一个名为“requests”的表,它代表一个图形。该请求表中有3列,分别是A、B和time。A -> B在time时刻发生。因此,每一行代表的是从A(请求者)到B(受请求者)的有向连接,发生在时间T(时间只用于组织数据,不会影响其他方面)。

如果说requests有1000000行数据,那么哪种查询方式更快呢?
Index(A, B) Index(A) and Index(B) Unique(A, B)?

谢谢大家!其中A、B是VARCHAR(32)类型(MD5的)

对不起,我忘记了一个典型的查询。
我需要能够查看已登录的用户A是否有任何请求!
我还需要搜索以验证用户是否接受了正确的请求,即A接受B的请求。

因此,查询语句将如下所示:

是否有新的请求?

SELECT B, time
FROM requests
WHERE A='$id';  

A 是否收到了 B 的请求?

SELECT time
FROM requests
WHERE A='$A' and B='$B';

1
“更快”取决于您计划如何搜索数据。一个典型的查询会是什么样子? - AJ.
Oko,刚刚更新了这些项目。抱歉我忘记放查询了。我可能会为新请求做比为B的请求做更多的请求。 - ThePrimeagen
我建议在A和B上都放置一个普通索引,这将为您提供良好的性能和所需的灵活性。不要使用唯一约束条件,MD5可能会发生冲突,但概率非常小,这会使事情变得太慢。最后一点是,MD5已不再安全,请“步行而不是奔跑”转向更安全的哈希函数,如SHA512。 - Johan
@Johan 如果我给我的 MD5 加盐会怎样? - ThePrimeagen
无论哈希的强度如何,都始终需要加盐。MD5 可能会发生碰撞,这就是为什么它不安全的原因。SHA512 是安全的。 - Johan
好吧,我做了MD5,但幸运的是,在我的系统中,所有哈希都通过一个单一的方法进行,所以将所有内容变为sha512应该不会太麻烦:) 谢谢你的提示。 - ThePrimeagen
2个回答

39

索引和唯一性是两个完全不同的概念。

索引
索引是一个隐藏的额外列,它保存了相同的数据并按指向实际数据的方式进行排序。使用索引可以:

  1. 快速查找特定的项
  2. 快速查找一系列项目(在x和y之间)
  3. 在使用order by时节省时间,因为项目已经预先排序
  4. 在使用group by时节省时间,因为group by需要匹配相同的项

这是一个普通的索引,它不介意重复值,除了主键始终是唯一的。

唯一(索引)
如果您想避免重复值,则可以在其上放置一个unique index。这将执行以上所有操作,但会在每次更新和插入时添加一个额外的检查,以检查该值是否已经存在于数据库中。如果您尝试在唯一列上插入重复行,则MySQL将给出一个错误并拒绝您的插入。
(您不能使一行unique而不使用索引)

使用索引会减缓插入和更新速度。
使用唯一索引会更加减缓速度。

然而,索引大大加速了select的速度。
Unique不会加速任何事情,它只是确保您不会意外插入重复的行。

何时使用索引,何时不要使用
不要在每个字段上都放置索引。如上所述,这会减慢您的insertupdate速度。
始终在连接条件上放置索引。并且认真考虑在您经常在where子句中使用的列上放置索引。
如果50%的行具有相同值,则MySQL将拒绝使用索引,因此请勿在布尔(Y/N)字段上放置索引,99%的时间它们不会起作用。

(低基数字段的索引是没有用处的) 始终为表分配一个主键
始终为您的表分配一个主键,最好是integer自增长类型。如果您不分配主键,MySQL将为您分配一个“隐藏”的主键(类型为integer自增长),但是您无法使用隐藏PK来加快报价或标识您的行,而且隐藏PK存在许多缓慢问题,使它们非常糟糕。
希望这可以帮助到您。 链接:
MySQL如何使用索引:http://dev.mysql.com/doc/refman/5.5/en/mysql-indexes.html
何时使用索引:http://www.howtoforge.com/when-to-use-indexes-in-mysql-databases
更多相关资料:http://www.databasejournal.com/features/mysql/article.php/1382791/Optimizing-MySQL-Queries-and-Indexes.htm
如果想了解更多有关MySQL的信息,请在此 lurk:http://planet.mysql.com/


1
顺便说一句,很棒的回答,我刚刚在查看其中一个旧问题。这是更具信息性的答案! :) - ThePrimeagen

3
在这种情况下,使用包含A和B的组合索引。确保A是索引中的第一个。这样当你运行这两个查询时,索引将用于两者。
更多关于组合索引的信息:

http://dev.mysql.com/doc/refman/5.5/en/multiple-column-indexes.html

此外,唯一性(A,B)并不重要,除非您的要求是B最多只能请求A一次

@AJ,我不明白在这里使用复合索引的用例,如果我只想查找B,那么使用复合索引就无法满足我的需求。请给我指点迷津? - Johan
2
@Johan - 请阅读手册。 "如果表具有多列索引,则优化器可以使用索引的最左前缀来查找行。例如,如果您在(col1、col2、col3)上有一个三列索引,则可以在(col1)、(col1、col2)和(col1、col2、col3)上进行索引搜索。" OP指定了两个查询:一个在A中搜索值,另一个在A、B中搜索值。如果需要仅在B上搜索,则OP需要指定,我将修改我的答案。 - AJ.
2
@AJ 我知道这一切,只是我讨厌复合键,因为它们会限制你的灵活性。最好从简单索引开始,等到你的数据库和前端设计稳定下来并且需要额外的5%速度或其他微小百分比时再引入复合键。虽然我非常不喜欢那些可怕的复合键,但我理解你的观点,从技术上讲你是正确的,如果不是因为我对复合键如此反感,我会给你点赞的。 - Johan
哈哈,你的诚实对我来说比点赞更有价值。干得好,先生。 - AJ.
你们两个都给出了非常好的答案。我想我会采纳Johan的建议,让内部工作稳定后再做复合索引。 - ThePrimeagen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接