2012-11-15 52 views
0

我有一個使PHP超時的SQL請求(mySQL 5.1.51)。 我想優化它,但我找不到缺少的東西。 請求爲:優化mysql查詢(使用或創建索引)

SELECT s_i.incident, 
     s.hostname, 
     a.application, 
     s_ie.problem_status, 
     s_i.open_time, 
     s_i.close_time, 
     s_ie.open_group, 
     s_ie.primary_assignment, 
     s_ie.closed_by_group, 
     s_ie.contact_first_name, 
     s_ie.contact_last_name, 
     s_ie.description, 
     s_ie.resolution, 
     s_ie.famille_1, 
     s_ie.famille_2, 
     s_ie.famille_3, 
     YEARWEEK(s_i.open_time)    AS 'semaine_ouverture', 
     DATE_FORMAT(s_i.open_time, '%Y-%m') AS 'mois_ouverture', 
     YEARWEEK(s_i.close_time)    AS 'semaine_cloture', 
     DATE_FORMAT(s_i.close_time, '%Y-%m') AS 'mois_cloture', 
     p.nom, 
     s.exploite_par, 
     t.environnement, 
     a.tdb 
FROM t_link_serveur_eac t USE KEY(nna) 
    INNER JOIN serveur   s ON s.id   = t.id_serveur 
    INNER JOIN plateau   p ON p.id   = t.id_plateau 
    INNER JOIN applications  a ON a.nna   = t.nna 
    INNER JOIN scope_i   s_i USE KEY (id_serveur) ON s_i.id_serveur = t.id_serveur 
    INNER JOIN scope_i_extended s_ie USE KEY (id_scope_i) ON s_ie.id_scope_i = s_i.id 
WHERE s_ie.problem_status  = 'Closed' 
AND s_ie.contact_first_name = 'AUTOMATE' 
AND s_ie.contact_last_name LIKE '%BEM%' 
AND p.id   = 4 
AND open_time >= CURDATE() - INTERVAL 52 WEEK AND open_time <= CURDATE() 
AND AND s_i.close_time < CURDATE() - INTERVAL DAYOFMONTH(CURDATE()) - 1 DAY 
ORDER BY mois_cloture 

當我問MySQL來解釋它,我有表s_ie的工會線型「ALL」。 我試圖創建/修改所有候選條件指數,但所有我試過沒有任何區別:

id select_type table type possible_keys key  key_len ref     rows Extra 
1 SIMPLE  p  const PRIMARY   PRIMARY 4  const     1  Using temporary; Using filesort 
1 SIMPLE  a  ALL  PRIMARY   NULL  NULL  NULL     957 
1 SIMPLE  t  ref  nna    nna  26  inspire.a.nna   10 Using where 
1 SIMPLE  s  eq_ref PRIMARY   PRIMARY 4  inspire.t.id_serveur 1 
1 SIMPLE  s_i  ref  id_serveur  id_serveur 4  inspire.t.id_serveur 135 Using where 
1 SIMPLE  s_ie eq_ref id_scope_i  id_scope_i 4  inspire.s_i.id  1  Using where 

s_ie有712.000線和S_I 740.000,所以我認爲這個問題來源於此結

這裏是表s_ie

CREATE TABLE IF NOT EXISTS `scope_i_extended` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `id_scope_i` int(11) NOT NULL, 
    `problem_status` varchar(16) NOT NULL, 
    `open_group` varchar(32) NOT NULL, 
    `primary_assignment` varchar(32) NOT NULL, 
    `closed_by_group` varchar(32) NOT NULL, 
    `contact_first_name` varchar(32) NOT NULL, 
    `contact_last_name` varchar(32) NOT NULL, 
    `description` text NOT NULL, 
    `resolution` text NOT NULL, 
    `famille_1` text NOT NULL, 
    `famille_2` text NOT NULL, 
    `famille_3` text NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `id_scope_i` (`id_scope_i`), 
    UNIQUE KEY `problem_status` (`id_scope_i`, `problem_status`, `contact_first_name`, `contact_last_name`), 
    KEY `contact_last_name` (`contact_last_name`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 

的結構和S_I的結構

CREATE TABLE IF NOT EXISTS `scope_i` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `incident` varchar(20) NOT NULL, 
    `statut` varchar(20) NOT NULL, 
    `id_serveur` int(11) NOT NULL, 
    `open_time` datetime NOT NULL, 
    `close_time` datetime DEFAULT NULL, 
    `affectation` varchar(50) NOT NULL, 
    `titre` varchar(200) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `incident` (`incident`), 
    KEY `serveur` (`id_serveur`), 
    KEY `serveur_open_time` (`id_serveur`,`open_time`), 
    KEY `id_serveur` (`id_serveur`,`close_time`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=738862 ; 

願意幫助/救救我嗎?

問候,

奧利維爾

+1

後查詢執行計劃以及請 –

+0

只是編輯的問題,並把它放在那裏,不要試圖在註釋 –

+0

的確增加產量,意見不能被格式化使執行計劃正確可讀。我編輯了一個添加它的問題。 –

回答

2

對不起,說明明顯,但我建議使用:的
"YEARWEEK(open_time) <= '201246' AND YEARWEEK(open_time) >= '201146'"

代替
"YEARWEEK(open_time) IN (...)"

IN總是慢又發生戲劇性。

+2

的確,這是我看到的一點,我也會要求開發者優化這個部分(也可以用BETWEEN) –

+0

@OlivierGérault您可能想要在dev上折騰這個鏈接:http:// use-the- index-luke.com/sql/where-clause/obfuscation/dates –

+0

謝謝,我讀過它並應用了這些建議,但由於超時,PHP仍然執行失敗。 –

1

在您的情況下,您將日期列包裝在Mysql函數中。 ex:YEARWEEK(open_time) and DATE_FORMAT(s_i.close_time, '%Y-%m-%d') 您應該避免這種情況,因爲Mysql似乎爲表格的每一行執行該函數。

您可以嘗試通過

s_i.close_time < CURDATE() - INTERVAL DAYOFMONTH(CURDATE()) - 1 DAY

YEARWEEK(open_time) IN ('201246', '201245'....)

通過它來取代

DATE_FORMAT(s_i.close_time, '%Y-%m-%d') < DATE_FORMAT(NOW(), '%Y-%m-01')

:(下面是條件GE所有記錄在一年內都有「open_time」。我不知道這是否是你的情況)

open_time >= CURDATE() - INTERVAL 1 YEAR AND open_time <= CURDATE()

+0

感謝您的建議。我申請了它們,這讓我節省了執行時間(1.5s vs 1.08s)。儘管如此,它仍然失敗。我忘了說結果是31.000行數組 –