【问题标题】:Multiple Column Index vs Multiple Indexes多列索引与多索引
【发布时间】:2011-11-07 20:37:21
【问题描述】:

我在 MySQL 数据库中有下表:

CREATE TABLE `secondary_images` (
  `imgId` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `primaryId` int(10) unsigned DEFAULT NULL,
  `view` varchar(255) DEFAULT NULL,
  `imgURL` varchar(255) DEFAULT NULL,
  `imgDate` datetime DEFAULT NULL,
  PRIMARY KEY (`imgId`),
  KEY `primaryId` (`primaryId`),
  KEY `imgDate` (`imgDate`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 ;

SQL 将如下所示:

SELECT imgURL, view FROM secondary_images 
WHERE primaryId={$imgId} ORDER BY imgDate DESC

如您所见,我制作了 primaryIdimgDate,索引键。我的想法是因为WHERE子句使用primaryId查询结果,而ORDER子句使用imgDate

我的问题是,像我现在这样使用多个索引会更好吗?或者我应该多列索引(目前我不太了解)?

这是我从 EXPLAIN 中得到的:

id = 1   
select_type = simple      
table = secondary_images         
type = ref
possible_keys = primaryId
key = primaryId
key_len = 5
ref = const
rows = 1
extra = Using where; Using filesort

注意:这不是使用多列索引,而是使用上表描述的结果。

【问题讨论】:

  • 你能发布选择的解释吗? :)
  • 请记住,indeces 不是免费的。如果您有多个索引,这意味着在每次插入或更新时,每个索引都需要更新。您需要权衡这些更新对性能的影响与您在检索时将看到的性能改进。
  • @stef:啊哈!你即将学到一些非常有用的东西。执行 SELECT 查询,但在其前面添加 explain 关键字:explain SELECT imgURL, view FROM secondary_images WHERE primaryId={$imgId} ORDER BY imgDate DESC。阅读Optimizing Queries With Explain
  • 这真的取决于你的桌子的大小。需要注意的是运行 EXPLAIN 并查看 MySQL 是否真的在使用您的索引。如果有很多重复项,它可能会决定不使用它。我有一本书称之为“扫描与搜索”问题。基本上,你会做类似SELECT COUNT (DISTINCT primaryId) FROM secondary_imagesSELECT COUNT(*) FROM secondary_images 的事情并计算比率。数字越大,“选择性”越高。如果数字太低,它不会成为有用的索引。
  • ALTER TABLE secondary_images DROP INDEX primaryId, DROP INDEX imgDate, ADD INDEX IdNDate (imgId DESC, primaryId ASC) ; 之类的东西应该可以解决问题。

标签: mysql database database-design indexing query-optimization


【解决方案1】:

您应该在 (primaryId, imgDate) 上使用多列索引,以便 MySQL 能够使用它来选择行和排序。

如果用于排序的所有列都不在用于选择的索引中,则 MySQL 使用“filesort”策略,该策略包括对所有行进行排序(如果没有太多行,则在内存中; 在磁盘上)。

如果用于排序的所有列都在索引中,则 MySQL 使用索引来获取行顺序(有一些限制)。

MySQL 为索引使用树结构。这允许直接按顺序访问键而无需排序。

多列索引基本上是列连接的索引。这允许 MySQL 找到匹配primaryId={$imgId} 的第一行,然后以正确的顺序直接访问所有其他行。

使用primaryId 上的单行索引,MySQL 可以找到与primaryId={$imgId} 匹配的所有行,但它会以不特定顺序查找行;所以它必须在那之后对它们进行排序。

请参阅 EXPLAINORDER BY Optimization

【讨论】:

  • 我不明白为什么 - 它是将一列与另一列进行比较,而不是将两列同时与另外两列进行比较。你能解释一下吗?
  • @arnaud576875 - 非常感谢!您是否有机会简要解释一下为什么在这种情况下这是最佳选择?另外,我将如何使用SQL 更改当前表以在(primaryId, imgDate) 上使用多列索引?
  • @arnaud576875 - 很好的解释。然而好奇; primaryId 不是唯一的。最多十个不同的整体可能具有相同的primaryId。这有什么改变吗?
  • 再次感谢!我会改的。
【解决方案2】:

您的解释如下所示:

[id] => 1 
[select_type] => SIMPLE 
[table] => secondary_images 
[type] => ref 
[possible_keys] => primaryId 
[key] => primaryId 
[key_len] => 5 
[ref] => const 
[rows] => 1 
[Extra] => Using where; Using filesort 

让我们来看看吧。

[id] => 1 

意味着我们正在谈论第一张桌子。您在语句中只调用了一个表。

[select_type] => SIMPLE 

我们正在做一个简单的 SELECT。

[table] => secondary_images 

有问题的表名。

[type] => ref 

选择类型,对连接最重要。

[possible_keys] => primaryId 

这是一个重要的字段:它显示了哪些键可以用来帮助查询更快地执行。在这种情况下,只有您的主键被认为是有用的。

[key] => primaryId 

这是一个重要字段:它显示最终使用了哪些键。在这种情况下,主键。

[key_len] => 5 
[ref] => const 
[rows] => 1 

猜测查询检查的行数。

[Extra] => Using where; Using filesort 

最重要的领域恕我直言。 - 使用 where:您正在使用 where 语句。很好。 - 使用文件排序:你查询的结果太大了,不可能 在内存中排序。 MySQL 必须将其写入文件,对文件进行排序,然后 然后输出。这意味着磁盘访问并将减慢一切。 添加可以帮助排序的索引通常会有所帮助,但要解决 “使用文件排序”是一个单独的章节。

【讨论】:

  • 哇,哇哇。非常感谢你。这样更容易理解。那么如何使用这些信息来确定多索引键是否可行呢?我不会要求您解决文件排序问题,因为您自己说这完全是另一个问题,但是切换到多索引键会对此有所帮助吗?
  • 您应该首先阅读有关说明的内容。 MySQL 站点是一个很好的起点,“High Performance MySQL”是我读过的最好的 MySQL 书籍。然后,了解它在很大程度上取决于您的表、存储引擎、您的配置(缓存大小等)以及表中的数据。所以,最好的测试方法是:复制表,并在副本上添加所需的索引。然后,比较解释。这就是为什么你需要理解解释:)
  • 再次感谢。非常感激。我去拿那本书。
  • 我通常更喜欢(免费)互联网资源(googleable、ctrl-f、书签)而不是死树,但这本书很棒。一些作者也有非常有趣的博客,他们的网站是percona.com
  • 我从未查看过那些互联网资源。感谢您的链接。我的 iPhone 确实有几个应用程序,它们是关于 MySQL 的 O'Reilly Media 书籍。我应该阅读更多。
猜你喜欢
  • 2010-09-15
  • 1970-01-01
  • 2018-07-27
  • 1970-01-01
  • 2020-05-06
  • 1970-01-01
  • 2019-03-22
  • 1970-01-01
相关资源
最近更新 更多