2011-06-27 57 views
1

我有一個查詢ORDER BY namename索引被忽略。優化MySQL連接查詢以刪除使用臨時並使用索引?

如何優化查詢以使用索引並擺脫EXPLAIN中的Using temporary

我有log-queries-not-using-indexes啓用,我看到這個查詢成千上萬次。

這裏的查詢:

SELECT l.parent_id, j.id, j.location_id, j.currency, j.frequency, ROUND((j.salary_min + j.salary_max)/2) as salary 
FROM jobs AS j 
JOIN location AS l 
    ON j.location_id = l.id 
WHERE j.salary_min !=0 
    AND j.status != 'Rejected'  
    AND l.published =1 
    AND date_sub(now(), interval 1 month) <= j.effected_date 
ORDER BY l.name 

的解釋:

+----+-------------+-------+--------+----------------------------------+---------------+---------+----------------------------+------+----------------------------------------------+ 
| id | select_type | table | type | possible_keys     | key   | key_len | ref      | rows | Extra          | 
+----+-------------+-------+--------+----------------------------------+---------------+---------+----------------------------+------+----------------------------------------------+ 
| 1 | SIMPLE  | j  | range | effected_date,location_id,status | effected_date | 9  | NULL      | 562 | Using where; Using temporary; Using filesort | 
| 1 | SIMPLE  | l  | eq_ref | PRIMARY       | PRIMARY  | 4  | esljw_joomla.j.location_id | 1 | Using where         | 
+----+-------------+-------+--------+----------------------------------+---------------+---------+----------------------------+------+----------------------------------------------+ 
2 rows in set (0.01 sec) 

而且表結構:

CREATE TABLE IF NOT EXISTS `jobs` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `location_id` varchar(255) NOT NULL, 
    `status` varchar(255) DEFAULT NULL, 
    `currency` varchar(255) DEFAULT NULL, 
    `salary_min` int(11) DEFAULT NULL, 
    `salary_max` int(11) DEFAULT NULL, 
    `effected_date` datetime DEFAULT NULL, 
    `frequency` varchar(255) NOT NULL DEFAULT '1', 
    PRIMARY KEY (`id`), 
    KEY `effected_date` (`effected_date`), 
    KEY `location_id` (`location_id`), 
    KEY `status` (`status`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=10130 ; 

CREATE TABLE IF NOT EXISTS `location` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(128) DEFAULT NULL, 
    `parent_id` int(11) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `name` (`name`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=304 ; 

回答

0
  1. 添加published + id綜合指數location
  2. 移動l.published =1條件的ON條款

這是什麼,你可以在你的情況下做的。但是,由於您不是通過主表進行排序,而是通過聯接表進行排序,因此,您將永遠無法擺脫using temporary

+0

你能解釋一下你的意思是由l.published = 1移動到ON條款? –

+0

@David Rogers:'ON j.location_id = l.id AND l.published = 1' – zerkms

+0

嗯......我試過了'alter table location add index id_pub(id,published)'和'alter table location add index pub_id出版,id)'。 EXPLAIN仍然選擇主'j.id'索引並且不使用新索引。 –

0

這是因爲您首先列出了job。更改表格的順序,如下所示:

SELECT l.parent_id, j.id, j.location_id, j.currency, j.frequency, ROUND((j.salary_min + j.salary_max)/2) as salary 
FROM location AS l 
JOIN jobs AS j ON j.location_id = l.id 
WHERE j.salary_min !=0 
AND j.status != 'Rejected'  
AND l.published =1 
AND date_sub(now(), interval 1 month) <= j.effected_date 
ORDER BY l.name 

試試看,併發布它如何去。

+0

是的,我已經嘗試過了。它仍然給出相同的解釋輸出。雖然謝謝! =) –

0

很多時候我已經做了查詢,在查詢中有適當的主表作爲第一個查詢,並且具有良好的索引,單獨添加STRAIGHT_JOIN可以修復查詢。因此,與現有的標準,你應該是好您的日期索引和使用,作爲主要標準......如

SELECT STRAIGHT_JOIN 
     L.Parent_ID, 
     J.id, 
     J.location_id, 
     J.currency, 
     J.frequency, 
     ROUND((J.salary_min + J.salary_max)/2) as Salary 
    FROM 
     jobs J 
     join Location L 
      on J.Location_ID = L.ID 
      AND L.Published = 1 
    WHERE 
      J.Effected_Date >= date_sub(now(), interval 1 month) 
     AND J.salary_min != 0 
     AND J.status != 'Rejected' 
    ORDER BY 
     L.name 
+0

哈,我從來沒有聽說過STRAIGHT_JOIN,我將不得不研究這個。 =)查詢工作的很好,但EXPLAIN仍然顯示'使用where;使用臨時;使用filesort' –