2016-09-19 67 views
3

我有一個總共400萬行的表。痛苦地緩慢索引列的MySQL查詢

當我運行下面的查詢,則需要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',它將在不到一秒內完成。

您能否請告知可能導致問題的原因,因爲所有列都被編入索引?

查詢說明:

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

創建:

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`); 

UPDATE:

我已經實現了以下一些問題的答案,他們幫助了很多!我會試圖找出哪個答案更適合我的情況。我將更新結果。

+1

只是好奇,如果你禁用'應用程序'的索引使用會發生什麼?即驅動日期而不是「應用程序」 –

+0

只是一個建議:將應用程序移動到另一個表並引用外鍵。然後,只需按應用程序的主鍵進行篩選即可。這很方便,尤其是如果在多行上使用相同的應用程序varchar。 – drodil

回答

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

第一個索引是正確的。查詢可能不會使用索引。 –

+0

@戈登可能不是,但這個想法看起來很可愛,我之前沒有見過(可能是因爲它不起作用) – Bohemian

1

嘗試增加1個指數對所有3列,而不是爲每一個可與執行計劃混淆優化單獨的索引:

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

這不是查詢的正確索引。 –

+0

@GordonLinoff我的不好。 – sagi