Mysql,在我的矩阵中,没有使用索引

时间:2015-12-29 19:15:49

标签: mysql

给出此表:

CREATE TABLE  `matrix` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `city1_id` int(10) unsigned NOT NULL DEFAULT '0',
  `city2_id` int(10) unsigned NOT NULL DEFAULT '0',
  `timeinmin` mediumint(8) unsigned NOT NULL DEFAULT '0',
  `distancem` mediumint(8) unsigned NOT NULL DEFAULT '0',
  `OWNER` int(10) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `city12_index` (`city1_id`,`city2_id`),
  UNIQUE KEY `city21_index` (`city2_id`,`city1_id`),
  KEY `city1_index` (`city1_id`),
  KEY `city2_index` (`city2_id`),
  KEY `ownerIndex` (`OWNER`),
  CONSTRAINT `PK_city_city1` FOREIGN KEY (`city1_id`) REFERENCES `city` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `PK_city_city2` FOREIGN KEY (`city2_id`) REFERENCES `city` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5118409 DEFAULT CHARSET=utf8;

有非常大量的数据。

这个SQL运行速度非常快:

select count(*) from city_matrix where owner=1

因为" owner"

上有索引
select count(*) from city_matrix where owner=1 order by id

这也非常快。但是这个:

select count(*) from city_matrix where owner=1 order by city1_id

需要几秒钟,但city1_id上也有索引!

解释说明了这一点:

1,' SIMPLE',' city_matrix','',' ref',' ownerIndex', ' ownerIndex',' 4',' const',169724,100.00,''

2 个答案:

答案 0 :(得分:1)

检索和索引申请的过程如下:

MySQL为密钥所有者检索的中间结果被“存储”在临时表中(根据结果的大小,在内存中或磁盘上)。

基于中间结果的直方图数据,可以应用索引。如果数据不够独特,则可以将索引丢弃为无用(例如:此169k结果中只有5个城市)。

解决

  • 使用提示应用索引:这被认为很差,因为它可能导致不必要的索引使用加速一个查询并减慢下一个查询(是的,索引可以使查询更慢);

  • 创建一个包含所有者和city1_id的多列索引。

最后一句话

order by上的COUNT(*)总是会减慢所有内容,因为order by不会改变您的结果。

答案 1 :(得分:1)

这是一个很好的问题。 MySQL根据许多不同的情况确定正确的索引。它的主要目标是找到最适合快速检索数据的索引。

select count(*) from city_matrix where owner=1 order by id

在这个查询中,MySQL确定where owner=1将结果减少到一个足够小的数字,按ID排序相对容易。例如,如果ID也是一个密钥(主要/唯一/索引),我怀疑它是,MySQL可以利用ID进行排序。

如果是这样的话:

select count(*) from city_matrix where owner=1 order by city1_id

MySQL仍然可以过滤掉所有者的所有记录,但需要时间来洗牌所有city1_id数据,以便您收到排序结果。由于需要时间,show processlist在此期间可能会向您显示查询正在重新排序数据。

为了帮助MySQL更快地完成工作,我们可以使用名为covering index的东西。覆盖索引具有查询中使用的所有字段,因此MySQL只需读取索引即可获取数据而无需触及基础表。 owner和city1_id上的复合索引将帮助MySQL使用一个索引来过滤数据,并再次使用相同的索引对数据进行排序,然后对其进行计数。

所以,让我们创建覆盖索引:

create index idx_city_matrix_city1_owner on city_matrix(owner, city1_id)

正如您所注意到的,MySQL花了一些时间来制作索引,一旦索引准备就绪,它可以很快地压缩数据以便为您提供数据。

编辑:重要的是要注意,当你像关于do的陈述那样计算(*)时,你不需要订购。结果集是标量 - 只有一个值。按任何字段排序不会影响您的计数。例如,计算表格中的所有水果将给你相同的结果,计算按其大小排序的表格上的所有水果。