2016-06-01 6 views
0

Auf dieser database (Mitarbeiter von MySQL Proben) optimieren ich diese Abfrage mit Index zu optimieren haben:Wie meine MySQL-Abfrage mit einem Index

SELECT t.title, 
     Avg(s.salary) salario_medio 
FROM titles t, 
     salaries s 
WHERE t.emp_no = s.emp_no 
     AND t.to_date > Now() 
     AND s.to_date > Now() 
GROUP BY t.title 
ORDER BY salario_medio DESC; 

Ich habe bereits diesen Index auf die „Gehälter“ Tabelle erstellen:

CREATE INDEX to_date_idx ON salaries(to_date); 

Aber die EXPLAIN gibt mir die Zeilen:

*************************** 1. row *************************** 
    id: 1 
    select_type: SIMPLE 
    table: s 
    type: range 
    possible_keys:PRIMARY,emp_no,to_date_idx 
    key: to_date_idx 
    key_len: 3 
    ref: NULL 
    rows: 370722 
    Extra: Using where; Using temporary; Using filesort 
    *************************** 2. row *************************** 
    id: 1 
    select_type: SIMPLE 
    table: t 
    type: ref 
    possible_keys: PRIMARY,emp_no 
    key: emp_no 
    key_len: 4 
    ref: employees.s.emp_no 
    rows: 1 
    Extra: Using where 

I WO old möchte nicht Using temporary und Using filesort verwenden.

INFO:

SHOW CREATE TABLE salaries; 

CREATE TABLE `salaries` 
    (
    `emp_no` INT(11) NOT NULL, 
    `salary` INT(11) NOT NULL, 
    `from_date` DATE NOT NULL, 
    `to_date` DATE NOT NULL, 
    PRIMARY KEY (`emp_no`, `from_date`), 
    KEY `emp_no` (`emp_no`), 
    KEY `to_date_idx` (`to_date`) 
) engine=myisam DEFAULT charset=latin1 show CREATE TABLE titles; 

CREATE TABLE `titles` 
    (
    `emp_no` INT(11) NOT NULL, 
    `title`  VARCHAR(50) NOT NULL, 
    `from_date` DATE NOT NULL, 
    `to_date` DATE DEFAULT NULL, 
    PRIMARY KEY (`emp_no`, `title`, `from_date`), 
    KEY `emp_no` (`emp_no`) 
) 
engine=myisam 
DEFAULT charset=latin1 
+1

Sie können die Sortierung nicht vermeiden. Das ORDER BY steht in einer berechneten Spalte. –

Antwort

1

Ich würde vorschlagen, die Abfrage wie folgt zu schreiben:

SELECT t.title, 
     (SELECT AVG(s.salary) 
     FROM salaries s 
     WHERE t.emp_no = s.emp_no AND 
       s.to_date > NOW() 
     ) as salario_medio 
FROM titles t 
WHERE t.to_date > NOW() 
ORDER BY salario_medio DESC; 

Diese Abfrage Vorteil von Indizes auf titles(to_date, title, emp_no) und salaries(emp_no, to_date) nehmen.

Dies beseitigt die für die Aggregation erforderliche Sortierung. Die Abfrage muss noch die endgültigen Ergebnisse sortieren.

+0

@ catmg97. . . Gibt es einen Grund, warum Sie diese Antwort nicht akzeptiert haben? –

0

Sie sollten explizite join Syntax verwenden, anstatt implizit. Das wird aber der Performance nicht helfen. Was helfen würde, ist das Ergebnis der Funktion NOW() in einer Variablen erfassen, auf diese Weise hat sie nur einmal ausgewertet werden, statt zweimal pro Zeile:

DECLARE @dtNOW DATETIME = NOW() 

SELECT  t.title 
,   AVG(s.salary) salario_medio 
FROM  titles t 
INNER JOIN salaries s 
     ON t.emp_no = s.emp_no 
WHERE  t.to_date > dtNOW 
     AND s.to_date > dtNOW 
GROUP BY t.title 
ORDER BY salario_medio DESC; 
0

Das 10-15 Jahre ein gutes Beispiel gewesen sein Vor, aber die Zeiten haben sich geändert.

Verwenden Sie InnoDB anstelle von MyISAM. Erwägen Sie, utf8 anstelle von latin1 zu verwenden. Fügen Sie einen Index für die Titel (to_date) hinzu. Löschen Sie den redundanten Index nur für (emp_no) in beiden Tabellen. Fügen Sie INDEX(title) hinzu.

(Ich bin damit einverstanden, dass Sie sollten die neuere JOIN Syntax verwenden.)

Und die AVG wahrscheinlich falsch sein, ohne zu Gordons Unterabfrage Version zu konvertieren. (Dieses Konstrukt existierte wahrscheinlich nicht, als die Probe entwickelt wurde.)