使用索引列痛苦地减慢MySQL查询速度

时间:2016-09-19 10:18:59

标签: mysql sql

我的桌子总共有400万行。

当我运行以下查询时,需要40秒才能完成

SELECT * FROM `traffic` 
WHERE `callstart_timestamp` >= '2016-09-01 00:00:00' 
AND `callend_timestamp` <= '2016-09-18 00:00:00' 
AND app = 'XXXX'
  总共416040,查询耗时40.0631秒。

如果我从查询中删除条件AND app = 'XXXX',它将在不到一秒的时间内完成。

您能否告知可能导致问题的原因,因为所有列都已编入索引?

查询EXPLAIN:

SIMPLE; traffic; NULL; ref; app,callend_timestamp,callstart_timestamp; app; 22; const; 1976467; 12.13; Using where;

CREATE:

CREATE TABLE `traffic` (
  `id` varchar(20) NOT NULL,
  `user_cli` varchar(15) NOT NULL,
  `ddi` varchar(15) DEFAULT NULL,
  `callstart_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `callend_timestamp` timestamp NULL DEFAULT NULL,
  `app` varchar(20) NOT NULL,
  `lang` char(2) NOT NULL DEFAULT 'en'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


ALTER TABLE `traffic`
  ADD PRIMARY KEY (`id`),
  ADD KEY `app` (`app`),
  ADD KEY `callend_timestamp` (`callend_timestamp`),
  ADD KEY `callstart_timestamp` (`callstart_timestamp`),
  ADD KEY `ddi` (`ddi`);

更新

我已经实现了下面的一些答案,他们帮了很多忙!我会试着找出哪个答案更适合我的情况。我会用结果更新。

2 个答案:

答案 0 :(得分:2)

标准答案是在所有3列上创建索引:

create index traffic_001 on traffic(app, callstart_timestamp, callend_timestamp)

遵循在索引列列表中将开放式范围匹配列放在精确匹配列之前的一般原则。

但还有一个我以前没见过的想法可能有用:

SELECT * FROM traffic 
WHERE callstart_timestamp between '2016-09-01 00:00:00' and callend_timestamp
AND callend_timestamp between callstart_timestamp and '2016-09-18 00:00:00' 
AND app = 'XXXX'

逻辑上,开始/结束值彼此限制。也许将这个事实编码到查询中将有助于不添加索引。

答案 1 :(得分:1)

尝试为所有3列添加1个索引,而不是为每个列添加单独的索引,这可能会使优化程序与执行计划混淆:

CREATE INDEX idx_1
ON traffic(app,callstart_timestamp,callend_timestamp);