在巨大的范围表上有效选择

时间:2016-06-06 10:12:21

标签: mysql query-optimization

我有一个mysql表,其中包含以下字段:rangeFromrangeTo

我想在联接中请求具有以下条件的行:rangeFrom >= ? AND rangeTo <=?

EXPLAIN SELECT *
FROM Version
JOIN Contract FORCE INDEX FOR JOIN (versionRangeFrom)
  ON Version.id >= Contract.versionRangeFrom
 AND Version.id <= Contract.versionRangeTo
WHERE Version.completedAt = '2016-06-06 10:00:01';

哪个mysql解释如下:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  Version ref PRIMARY,completedAt completedAt 6   const   1   NULL
1   SIMPLE  Contract    ALL versionRangeFrom    NULL    NULL    NULL    640744  Range checked for each record (index map: 0x8)

所以它必须工作640744行,大约需要1-2秒。

但是,在queryworks中插入版本ID

EXPLAIN SELECT *
FROM Contract
WHERE 5 >= Contract.versionRangeFrom AND 5 <= Contract.versionRangeTo;

然后这样解释:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  Contract    range   versionRangeFrom    versionRangeFrom    4   NULL    534 Using index condition; Using where

所以在这种情况下,mysql只能运行534行,而且只需要大约30ms。

那么我该如何正确地准备这样的范围检查。在这些情况下,似乎mysql无法使用索引。我可以通过使用2个查询解决它,但我宁愿有一个。

这里有更多模式:

 CREATE TABLE `Version` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `completedAt` datetime DEFAULT NULL,
  `createdAt` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `completedAt` (`completedAt`)
) 

CREATE TABLE `Contract` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `contractId` bigint(20) unsigned NOT NULL,
  `startAt` bigint(20) NOT NULL DEFAULT '0',
  `endAt` bigint(20) NOT NULL DEFAULT '0',
  `tradeStartAt` bigint(20) NOT NULL DEFAULT '0',
  `tradeEndAt` bigint(20) NOT NULL DEFAULT '0',
  `latestAiId` bigint(20) NOT NULL DEFAULT '0',
  `type` varchar(4) COLLATE utf8_unicode_ci NOT NULL,
  `daPreis` int(11) NOT NULL DEFAULT '0',
  `lastTradePreis` int(11) NOT NULL DEFAULT '0',
  `lastTradeVol` int(11) NOT NULL DEFAULT '0',
  `VWAID` double NOT NULL DEFAULT '0',
  `versionRangeFrom` int(10) unsigned NOT NULL,
  `versionRangeTo` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `tradeStartAt` (`tradeStartAt`),
  KEY `contractId` (`contractId`),
  KEY `versionRangeFrom` (`versionRangeFrom`)
)

1 个答案:

答案 0 :(得分:0)

与&#39; 5&#39;不同的值。不需要只看534行。

问题(x < from AND x > to)非常重要,而且没有简单的答案。

缩小表格大小会有所帮助。当一些较小的数据类型就足够时,不要使用BIGINT(8个字节)。

也许唯一真正的解决方案是对架构和代码进行重大改进。请参阅my blog

修改

某些情况下,此子查询可以有效地用于查找相关行:

( SELECT Contract.id FROM ...
      WHERE Version.id >= Contract.versionRangeFrom
      ORDER BY versionRangeFrom
      LIMIT 1 )