2016-06-01 6 views
0

На этом database (сотрудники из образцов MySQL) Я должен оптимизировать этот запрос, используя индекс:Как оптимизировать мой запрос MySQL с индексом

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; 

Я уже создать этот индекс на «зарплате» таблица:

CREATE INDEX to_date_idx ON salaries(to_date); 

Но EXPLAIN дает мне эти строки:

*************************** 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 им uld, как не использовать Using temporary и Using filesort.

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

Вы не можете избежать сортировки. «ORDER BY» находится в вычисленном столбце. –

ответ

1

Я хотел бы предложить писать запрос, как это:

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; 

Этот запрос может воспользоваться индексами на titles(to_date, title, emp_no) и salaries(emp_no, to_date).

Это устраняет сортировку, необходимую для агрегации. Запрос по-прежнему должен сортировать окончательные результаты.

+0

@ catmg97. , , Есть ли причина, по которой вы не приняли этот ответ? –

0

Вы должны использовать явный синтаксис join, а не неявный. Однако это не поможет. Что помогло бы, получающий результату функции NOW() в переменном, что так оно и есть только оценить один раз, а не два раза в строку:

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

Это, возможно, был хорошим примером 10-15 лет назад, но времена изменились.

Используйте InnoDB вместо MyISAM. Рассмотрите возможность использования utf8 вместо latin1. Добавьте индекс в заголовки (to_date). Избавляйтесь от избыточного индекса только в (emp_no) в обеих таблицах. Добавить INDEX(title).

(я согласен, что вы должны использовать новую JOIN синтаксис.)

Причем, AVG, вероятно, будет неправильным без преобразования в подзапроса версии Гордона. (Эта конструкция, вероятно, не существовала, когда образец был разработан.)