假设我有一个由组中的产品组成的大型数据库。假设共有5组,每组有100,000个产品。产品ID是随机整数(组ID也是如此)
我需要在特定组中找到产品。我的问题是哪个主键更有效:
(sid, pid)
(pid, sid)
sid,pid是直观的,但是当按此顺序搜索时,MySQL必须从500,000行中隔离100,000,然后在100,000中找到一个数字。另一方面,(pid, sid)
对我来说听起来更优,因为它会迫使mysql在第一阶段不创建大的100,000组,而是直接转到正确的项目(如果有相似的话,最多可以有5个项目)不同的cids中的pids)。
#2确实更快吗?
更新: 好。我把一张真正的桌子复制了两份。 table0有主键sid,pid。 table1有pid,sid。
查询结果:
解释select * from items0,其中sid = 22746,pid = 2109418034 1,'SIMPLE','items0','ref','PRIMARY','PRIMARY','8','const,const',14,''
解释select * from items1,其中sid = 22746和pid = 2109418034
1,'SIMPLE','items1','ref','PRIMARY','PRIMARY','8','const,const',11,''
又一次更新: 我还将两个键添加到同一个表中并运行explain。明白啦: (主要以sid_pid1开头,Index2以pid1,sid开头)
1,'SIMPLE','items','ref','PRIMARY,index_2','index_2','8','const,const',13,''
我不确定,我可以从这个测试中得出什么结论?
答案 0 :(得分:8)
不要猜,测试。
复制数据库,尝试两个密钥,并自行查找。然后发布您的结果,并附上免责声明,用户应该使用他们的数据集自行尝试,但这是您的结果。
答案 1 :(得分:4)
将两个密钥添加为非主要密钥(或者将一个密钥添加为主要密钥,将一个密钥添加为非主要密钥),然后将“EXPLAIN”添加到前面,运行所需的查询。这将使MySQL向您显示它所选择的密钥。
答案 2 :(得分:4)
SQL DBMS查询的性能很大程度上取决于很多因素 - 表(或索引)的碎片化程度,数据/索引统计数据的新鲜度和数量,数据缓存的大小/ CPU数量/内存,表中有多少行,查询结构等等。
虽然分析查询是性能调优的必要部分,但仅凭它还不够 - 它必须是更大的查询优化策略的一部分。由于查询优化过程的非确定性,在一般情况下说“测试并看到”并不是非常有用(并且在我看来有时很危险!)。一天运行它可以很好,下一个慢(反之亦然)。
如果不了解MySQL索引构建的基本原理,将使用哪些查询,以及查询将如何使用索引,任何临时测试都是最好的情况,幸运猜测和最坏情况下的滴答时间炸弹。< /强>
在这种情况下,由于MySQL B-Trees的构造方式,有一个经验法则。在MySQL内部页面:http://forge.mysql.com/wiki/MySQL_Internals_MyISAM#The_.MYI_file中,您可以看到,对于两列上的非唯一BTREE索引,MySQL将按您指定的顺序存储连接值。在那个特定的例子中,他们存储了ASCII(或UNICODE),但是在整数值的情况下,它会做类似的事情(如果你足够勇敢,打开一个十六进制编辑器并解码实际值!)(这里也参考{{3} })。
因此,经验法则是首先放置最多选择性(ref http://dev.mysql.com/doc/refman/5.0/en/multiple-column-indexes.html)值,因为这为查询处理器提供了最多的信息来缩小行数#处理。放置一个选择性较小的密钥FIRST会强制优化器考虑更多的行,除非您确实需要这些行,否则设计将是次优的。
还要重温Eric所说的:MySQL(或其他DBMS')可以使用任何/所有密钥以增加方式来帮助缩小搜索范围 - 例如如果你在(A,B,C)上放置索引,那么具有WHERE A = .. B =的查询可以使用它(取决于),使用WHERE A =的查询可以使用它,但是要求WHERE C =的查询不能(通常)。
所以,它还取决于你的查询的性质 - 如果你总是要求WHERE pid = AND sid =那么最有选择性的应该先去(产品ID),但如果你经常要求WHERE sid = XXXX by本身,然后sid应该先行(或者如果有不同的数量,则只为该情况创建另一个索引)。这里的权衡取决于时间/空间 - 有一个额外的索引将满足不同类别的查询,代价是额外的磁盘空间和增加的写入I / O.
最后,如果你正在使用INNODB,你可以指定一个“聚集”索引,它实际上对磁盘上的行进行排序(MyISAM表基本上是堆)。如果你通过sid对pid上的行进行聚类,那么它实际上将它们组合在一起,这样你就可以一次获取整个产品的BLOCKS(或页面),这将比单独使用BTREE的I / O少得多(参考http://www.akadia.com/services/ora_index_selectivity.html })
所以,你可以看到为什么“测试它并看到”是有用的,但是如果你不了解MySQL索引基础知识,你会错过一整套优化。
答案 3 :(得分:1)
正如汤姆所说,测试并找出答案,但这可能取决于您将要进行的查询类型。我假设您将使用此表将产品加入群组?
如果您的查询主要是“哪个群组是此产品”类型,那么(pid,sid)可能会最快。
如果他们是“给我这个组中的所有产品”类型,那么(sid,pid)可能会更快。