2017-07-28 15 views
1

我有一個相當簡單的查詢(用作greatest-n-per-group情境中的子查詢)。 state_id是主鍵 - 其他的都不是唯一的。在最大n組子查詢中使用範圍過濾器的性能非常差

SELECT max(states.state_id) AS max_state_id 
FROM states 
WHERE states.created >= '2017-06-10 21:53:38.977455' 
    AND states.created < '2017-06-26 07:00:00' 
GROUP BY states.entity_id; 

的問題是,這種查詢是驚人,慢,我不相信多列索引的任何命令可以解決這個問題它的編寫方式。我們試圖在這裏做的是得到每個entity_id最新state_id兩個時間戳之間:它總是以using where; using index; using temporary; using filesort

如果現在還不清楚結束。

我們可以做的,而不是一個max(states.created)(而不是max(states.state_id)),這可能是更好的,無論如何,但我沒有state_id外部查詢加入上。

這裏是包括外部分給予充分的背景下,全面查詢:

SELECT states.state_id AS states_state_id, states.domain AS states_domain, states.entity_id AS states_entity_id, states.state AS states_state, states.attributes AS states_attributes, states.event_id AS states_event_id, states.last_changed AS states_last_changed, states.last_updated AS states_last_updated, states.created AS states_created 
FROM states INNER JOIN (
    SELECT max(states.state_id) AS max_state_id 
    FROM states 
    WHERE states.created >= '2017-06-10 21:53:38.977455' AND states.created < '2017-06-26 07:00:00' GROUP BY states.entity_id 
) AS anon_1 ON states.state_id = anon_1.max_state_id; 

當然必須有辦法以這種方式來重寫此查詢允許索引做一個鬆散索引掃描...

+0

爲什麼外層查詢包含所有其他列?另外,如果更高的'state_id'並不意味着它稍後被創建,那麼'MAX'查詢可能是錯誤的。 –

+0

@FelixPamittan:好的,外層查詢只是返回應用程序需要的值。爲了簡潔起見,我們可以用'select *'替換所有的。至於創建的vs state_id,我確實同意,並在我的問題中提到過。但是,如果我們沒有得到state_id的最大值,我不確定外部查詢將如何加入到它 – OverloadUT

+0

您是否在查詢所有'entity_id'的同一時間段? – Horaciux

回答

0

首先,這個查詢:

SELECT max(s.state_id) AS max_state_id 
FROM states s 
WHERE s.created >= '2017-06-10 21:53:38.977455' AND 
     s.created < '2017-06-26 07:00:00' 
GROUP BY s.entity_id; 

我想,以確保您在states(created, entity_d, state_id)有一個索引。只是爲了看看這是否有幫助。

其次,考慮重寫查詢爲:

SELECT max(s.state_id) AS max_state_id 
FROM states s 
WHERE s.created >= '2017-06-10 21:53:38.977455' AND 
     s.created < '2017-06-26 07:00:00' AND 
     s.state_id = (SELECT MAX(s2.state_id) 
        FROM states s2 
        WHERE s2.entity_id = s.entity_id AND 
          s2.created >= '2017-06-10 21:53:38.977455' AND 
          s2.created < '2017-06-26 07:00:00' 
        ); 

對於此查詢,您想對指數:states(entity_id, created, state_id)states(created, entity_id, state_id)(列的索引的順序很重要)。

+0

不幸的是,第一個索引不起作用。問題在於第二個維度是一個_range_過濾器,未按第三維聚合函數進行分組。這使得索引無法用於當前查詢的方式。至於查詢重寫 - 我正在測試... – OverloadUT

+0

好吧,那第二個查詢似乎不工作。我實際上無法弄清楚它想做什麼。我可以說,如果沒有索引,它已經運行了13個小時,即使我們可以通過索引獲得它的性能,它也會讓我覺得很腥。 – OverloadUT