为什么在MySQL表中添加重复索引导致查询执行时间更长?

时间:2016-09-16 08:19:06

标签: mysql

也许索引不相关,但我遇到了一个奇怪的问题。

这是我的选择查询:

SELECT DISTINCT completeAddress FROM DB_M3_Medium.AvailableAddressesV3 where postNr = 1050 ORDER BY completeAddress ASC;

我的索引:

create index postNrAndAddress_idx on DB_M3_Medium.AvailableAddressesV3 (completeAddress);
create index postNr_idx on DB_M3_Medium.AvailableAddressesV3 (completeAddress);
create index completeAddress_idx on DB_M3_Medium.AvailableAddressesV3 (completeAddress);

除此之外,我在自动增量ID(idIndex)上有一个PK。

在任何手动创建的索引出现之前,select查询的执行时间是2.4秒。

然后我创建了索引(逐个):

  • 第一个索引 - 选择语句执行时间 - 2.1s
  • 第二个索引 - 选择 声明执行时间 - 2.8s
  • 第三个索引 - 选择语句 执行时间 - 12.7秒

刚刚发生了什么事?

修改

谢谢你们的评论。我的解释陈述结果:

+----+-------------+----------------------+-------+-----------------------------------------------------+---------------------+---------+-----+---------+-------------+
| id | select_type |        table         | type  |                    possible_keys                    |         key         | key_len | ref |  rows   |    Extra    |
+----+-------------+----------------------+-------+-----------------------------------------------------+---------------------+---------+-----+---------+-------------+
|  1 | SIMPLE      | AvailableAddressesV3 | index | postNrAndAddress_idx,postNr_idx,completeAddress_idx | completeAddress_idx |     363 |     | 3526406 | Using where |
+----+-------------+----------------------+-------+-----------------------------------------------------+---------------------+---------+-----+---------+-------------+

表格结构:

+------------------+--------------+------+-----+---------+----------------+
|      Field       |     Type     | Null | Key | Default |     Extra      |
+------------------+--------------+------+-----+---------+----------------+
| vej_Navn         | varchar(70)  | YES  |     |         |                |
| husNr            | varchar(20)  | YES  |     |         |                |
| husbogstav       | varchar(50)  | YES  |     |         |                |
| etage            | varchar(30)  | YES  |     |         |                |
| side_DoerNr      | varchar(20)  | YES  |     |         |                |
| stedNavn         | varchar(50)  | YES  |     |         |                |
| postNr           | varchar(15)  | YES  | MUL |         |                |
| postDistrikt     | varchar(50)  | YES  |     |         |                |
| lev_Adresse_UUID | varchar(50)  | YES  |     |         |                |
| fiberstatus      | varchar(15)  | YES  |     |         |                |
| kommune_nr       | varchar(35)  | YES  |     |         |                |
| vej_Kode         | varchar(35)  | YES  |     |         |                |
| completeAddress  | varchar(120) | YES  | MUL |         |                |
| randomSalt       | varchar(5)   | YES  |     |         |                |
| id               | int(11)      | NO   | PRI |         | auto_increment |
+------------------+--------------+------+-----+---------+----------------+

创建表格查询:

  CREATE TABLE `AvailableAddressesV3` (
  `vej_Navn` varchar(70) COLLATE utf8_unicode_ci DEFAULT NULL,
  `husNr` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  `husbogstav` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `etage` varchar(30) COLLATE utf8_unicode_ci DEFAULT NULL,
  `side_DoerNr` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
  `stedNavn` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `postNr` varchar(15) CHARACTER SET utf8 DEFAULT NULL,
  `postDistrikt` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `lev_Adresse_UUID` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  `fiberstatus` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL,
  `kommune_nr` varchar(35) COLLATE utf8_unicode_ci DEFAULT NULL,
  `vej_Kode` varchar(35) COLLATE utf8_unicode_ci DEFAULT NULL,
  `completeAddress` varchar(120) COLLATE utf8_unicode_ci DEFAULT NULL,
  `randomSalt` varchar(5) COLLATE utf8_unicode_ci DEFAULT NULL,
  `id` int(11) NOT NULL AUTO_INCREMENT,
  UNIQUE KEY `idIndex` (`id`),
  KEY `postNrAndAddress_idx` (`postNr`,`completeAddress`),
  KEY `postNr_idx` (`postNr`),
  KEY `completeAddress_idx` (`completeAddress`)
) ENGINE=InnoDB AUTO_INCREMENT=3552718 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

2 个答案:

答案 0 :(得分:1)

根据您的EXPLAIN输出,查询正在使用completeAddress_idx,可能是因为排序/不同,但我猜测postNr = 1050的行很少(在哥本哈根,右边) ?)因此使用postNr_idxpostNrAndAddress_idx应该更有效率(几百行的排序/分离应该几乎是即时的)。有些事情使得查询执行计划程序错过了最佳查询。

我自己从未尝试过,但您可以尝试更新表统计信息的ANALYZE TABLE语句,例如关键基数,这可能会改变优化程序的工作方式。

要不然,或者我错过了一些简单的东西 - 这似乎很可能:)

修改

在调试时,强制MySQL使用特定索引会很有用。试试FORCE/USE INDEX hint

答案 1 :(得分:1)

我绝不会指望这可能是一个问题,或者至少我会在WorkBenchJDBC收到错误或至少发出警告的通知。

我的选择查询应如下所示:

SELECT DISTINCT completeAddress FROM DB_M3_Medium.AvailableAddressesV3 where postNr = '4000' ORDER BY completeAddress ASC;

区别在于postNr的数据类型。在我没有将其包裹在'之前。

这疯狂改进了选择,然后当我删除ORDER BY时,执行时间下降到0.07秒。

所以基本上发生的事情是,SELECT查询没有使用任何索引,因为没有一个索引是合适的。当我执行EXPLAIN时,我收到的是我的Key列。我试图FORCE它,但它没有任何区别。

然后我发现了这个:local variable declaration

他在第二个答案中提到了它。