简体   繁体   English

为什么MySQL不使用索引?

[英]Why does MySQL not use the index?

I have a table: 我有一张桌子:

CREATE TABLE  `ais`.`last_location` (
  `timestamp` timestamp NOT NULL default '0000-00-00 00:00:00',
  `message_type` tinyint(4) NOT NULL default '0',
  `repeat_indicator` tinyint(4) NOT NULL default '0',
  `mmsi` int(11) NOT NULL default '0',
  `navigation_status` tinyint(4) NOT NULL default '0',
  `rot` tinyint(4) NOT NULL default '0',
  `sog` smallint(6) NOT NULL default '0',
  `position_accuracy` tinyint(4) NOT NULL default '0',
  `longitude` int(11) NOT NULL default '0',
  `latitude` int(11) NOT NULL default '0',
  `cog` smallint(6) NOT NULL default '0',
  `hdg` smallint(6) NOT NULL default '0',
  `time_stamp` tinyint(4) NOT NULL default '0',
  `maneuver_indicator` tinyint(4) NOT NULL default '0',
  `spare` tinyint(4) NOT NULL default '0',
  `raim_flag` tinyint(4) NOT NULL default '0',
  `sotdma_sync_state` tinyint(4) NOT NULL default '0',
  `sotdma_slot_timeout` tinyint(4) NOT NULL default '0',
  `sotdma_slot_offset` smallint(6) NOT NULL default '0',
  PRIMARY KEY  USING BTREE (`mmsi`),
  KEY `Index_2` (`timestamp`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;"

And I explain to queries: 我向查询解释:

EXPLAIN SELECT * 
FROM last_location 
WHERE `timestamp` BETWEEN '2013-01-01 12:00:00' AND '2013-06-03 11:30:00'

1, 'SIMPLE', 'last_location', 'range', 'Index_2', 'Index_2', '4', '', 83, 'Using where'

EXPLAIN SELECT * 
FROM last_location 
WHERE `timestamp` BETWEEN '2013-01-01 12:00:00' AND '2013-06-03 11:40:00'

1, 'SIMPLE', 'last_location', 'ALL', 'Index_2', '', '', '', 478, 'Using where'

Can anyone tell me the difference between searching to 11:30 and 11:40? 谁能告诉我搜索11:30和11:40之间的区别? When using 11:30 everything is looking okay I think? 我认为使用11:30时一切都很好吗? But when using 11:40 it does not use the index anymore? 但是当使用11:40时,它不再使用索引了吗?

Query planners reserve the right to ignore an index if statistics suggest that you'll be visiting the whole table to fetch the matching rows. 如果统计数据表明您将访问整个表以获取匹配的行,则查询计划人员保留忽略索引的权利。

The reason is, it's cheaper to sequentially read disk pages one by one while filtering the rows you need, than it is to bounce back and forth on disk pages in the order indicated by the index. 原因是,在过滤所需行的同时逐一顺序读取磁盘页面比按索引指示的顺序在磁盘页面上来回弹跳要便宜。

Index scan takes more I/O per record (as it needs to visit the table itself in a nested loop, which is generally random access I/O) but allows to use less records (only those satisfying the sargable condition). 索引扫描每条记录需要更多的I / O(因为它需要在嵌套循环中访问表本身,通常是随机访问I / O),但允许使用更少的记录(仅满足可满足条件的记录)。

Table scan inevitably scans the whole table but takes much less I/O per record (it's a sequential scan over one .MYD file). 表扫描不可避免地会扫描整个表,但是每条记录占用的I / O少得多(这是对一个.MYD文件的顺序扫描)。

MySQL's optimizer is aware of that and may choose one or another access path depending on the selectivity of the sargable condition: more selective conditions are likely to benefit form the index scan, less selective would be more efficient with a full table scan. MySQL的优化器意识到这一点,并可以根据可设置条件的选择性来选择一个或另一个访问路径:索引扫描可能会受益于更多的选择条件,而全表扫描会降低选择性的选择效率。

This is what you are observing. 这就是您正在观察。

Note that the optimizer's solution may be inefficient, especially if you have some specific data distribution, I/O subsystem layout etc. You may force the index scan: 请注意,优化器的解决方案可能效率不高,尤其是在您具有某些特定的数据分布,I / O子系统布局等的情况下。您可以强制进行索引扫描:

SELECT  *
FROM    last_location FORCE INDEX (Index_2)
WHERE   `timestamp` BETWEEN '2013-01-01 12:00:00' AND '2013-06-03 11:40:00'

if you believe the index is more efficient. 如果您认为索引更有效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM