MySQL没有使用带有选择性INT键的索引

时间:2015-06-16 05:31:38

标签: mysql performance indexing

我已经创建了下面列出的表格测量值。 该表定期写入,并在几天后迅速增长到包含数百万行。 读:我只需要测量的精确时间及其值(unix_epoch和值)。

为了提高性能,我添加了date_from_epoch列,这是从unix_epoch中提取的日期(测量精确时间),格式为:yyyymmdd。它应该具有良好的选择性(在将多天的测量结果写入表格之后)并且我将其用作索引的关键字。我希望只扫描我想要读取测量的天数,而不是扫描表中的所有日期(例如:10天后,如果每天添加1,000,000,我希望只扫描1,000,000行,如果我需要在一天内包含数据,而不是10,000,000)。

我也有:

  • 使用innoDB作为引擎
  • 通过哈希将表分区为10个文件以帮助I / O
  • 确保我的查询中使用的类型与列类型相同(或者我的验证错误了?)。

问题: 测量表在测量表中滴流2天后,我进行了测试。 使用EXPLAIN,我看到我的读取查询不使用索引。为什么查询没有使用索引?

表创建于:

CREATE TABLE measurements(
date_from_epoch INT UNSIGNED,
unix_epoch INT UNSIGNED,
application_name varchar(255),
environment varchar(255),
metric_name varchar(255),
host_name varchar(1024),
value FLOAT(38,3)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
PARTITION BY HASH(unix_epoch)
PARTITIONS 10;

CREATE TRIGGER write_epoch_day 
BEFORE INSERT ON measurements
FOR EACH ROW
SET NEW.date_from_epoch = FROM_UNIXTIME(NEW.unix_epoch, '%Y%m%d');

ALTER TABLE measurements ADD INDEX (date_from_epoch);

查询是:

EXPLAIN SELECT * FROM measurements
WHERE date_from_epoch >= 20150615 AND date_from_epoch <= 20150615
AND unix_epoch >= 1434423478 AND unix_epoch <= 1434430678
AND BINARY application_name = 'all'
AND BINARY environment = 'prod'
AND BINARY metric_name = 'Internet availability'
AND (BINARY host_name = 'kitkat' )
ORDER BY unix_epoch ASC;

解释给出:

id  select_type         table           type        possible_keys       key         key_len         ref         rows       Extra     
-------------------------------------------------------------------------------------------------------------------------------------------------------
1   SIMPLE              measurements    ALL         date_from_epoch                                             118011     Using where; Using filesort 

感谢阅读和头疼!

3 个答案:

答案 0 :(得分:0)

可以选择在MYSQL中使用 FORCE INDEX

请参阅this以便更好地理解。

答案 1 :(得分:0)

谢谢Sashi!

我已将查询修改为

Summer

解释说仍然&#34;使用在哪里;使用文件排序&#34;但扫描的行数现在下降到67,906,相比之下最初扫描的118,011(这很棒)。

虽然date_from_epoch = 20150615的行数是113,182。我现在想知道为什么扫描的行数不是113,182(不是我希望它上升,但我想了解mysql做了什么来进一步优化执行)。

答案 2 :(得分:0)

很多事情需要解决:

  • 不要使用PARTITION BY HASH;它无济于事。
  • 由于您在分区键上有一个范围,因此它必须触及所有分区。请参阅EXPLAIN PARTITIONS SELECT ...
  • 不要为额外的epoch_from_date和Trigger而烦恼;只需对unix_epoch进行比较。 (参见所需转换程序手册。)
  • 请勿使用BINARY。而是将列指定为COLLATION utf8_bin。性能会好很多。
  • 规范化(或转换为ENUM)这些字段:application_name,environment,metric_name,host_name。数百万行,你所拥有的东西不必要地笨重。 (我假设这些字段只有几个不同的值。)节省的空间将使SELECT运行得更快。
  • FLOAT(38, 3)有一个额外的(不必要的?)舍入。只需使用FLOAT
  • (进行上述更改后)INDEX(application_name, environment, metric_name, host_name, unix_epoch)会非常有用,至少对于那个查询而言。它会比你要问的INDEX明显更好。