2013-06-03 42 views
1

我有一个表:为什么MySQL不使用索引?

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;" 

我要查询解释:

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' 

谁能告诉我搜索到11:30和11:40之间的区别?当使用11:30时,一切都看起来没问题,我想?但是在使用11:40时它不再使用索引了?

+1

推测mysql根据它在表上的统计数据计算出它在这种情况下不值得使用索引。执行时间有重大差异吗? – nos

+0

[MySql中的BETWEEN操作索引]的可能的重复(http://stackoverflow.com/questions/2175163/index-for-between-operation-in-mysql) – Vyktor

+0

表中有多少行? – ankurtr

回答

1

如果统计信息表明您将访问整个表以获取匹配行,则查询计划人员保留忽略索引的权利。

原因在于,按照索引所指示的顺序在磁盘页面上来回跳动,而在过滤所需的行时,依次逐个读取磁盘页面会更便宜。

+0

我的问题太快了,数据库在这个时候填满了,现在这个索引现在一直在使用(我所见过的)。结论是,MySQL正在自我优化,结果索引不被少量的行使用。 – ralphvn86

1

索引扫描每个记录需要更多I/O(因为它需要通过嵌套循环访问表本身,通常是随机访问I/O),但允许使用更少的记录(只有那些满足可靠条件的记录) 。

表扫描不可避免地扫描整个表,但每个记录的I/O需要少得多(这是对一个.MYD文件的顺序扫描)。

MySQL的优化器意识到这一点,并可能根据可选状态的选择性选择一个或另一个访问路径:更多的选择性条件可能从索引扫描中受益,更少的选择性对于全表扫描更有效。

这就是你正在观察的。

注意,优化的解决方案可能是低效的,特别是如果你有一些特定的数据分布,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' 

如果您认为该指数更高效。

+0

我想我明白了不同的行为,MySQL只是决定索引是否使用有趣,或者不是。 – ralphvn86