给出此表:
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,''
答案 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的陈述那样计算(*)时,你不需要订购。结果集是标量 - 只有一个值。按任何字段排序不会影响您的计数。例如,计算表格中的所有水果将给你相同的结果,计算按其大小排序的表格上的所有水果。