2017-02-15 10 views
0

挨拶、このクエリを高速化することは可能ですか?

私はMySQLには新しく、特にクエリを作成しています。クエリをより速く実行できるかどうかは疑問でした。私はここでDBが利用できる従業員を使用しています:今https://github.com/datacharmer/test_db

私は次のように答えるために必要な生成するために持っていたクエリを:「各部門の•、各年代に生まれた従業員のリストの数とその平均給与」

これは私が思いついたものです:

SELECT DISTINCT d.dept_name, count(e.emp_no), AVG(s.salary), ROUND(YEAR(e.birth_date), -1) AS birth_date 
FROM employees e, departments d, salaries s, dept_emp de 
WHERE de.emp_no = e.emp_no AND de.dept_no = d.dept_no 
    AND e.emp_no = s.emp_no 
    GROUP BY d.dept_name, 
    ROUND(YEAR(e.birth_date), -1); 

教授が望んだ結果が得られますが、実行には約11秒かかりますが、かなり遅いです。クエリの実行に時間がかかる何かがありますか?

編集:説明

テーブル:

mysql> explain dept_emp_latest_date; 
+-----------+---------+------+-----+---------+-------+ 
| Field  | Type | Null | Key | Default | Extra | 
+-----------+---------+------+-----+---------+-------+ 
| emp_no | int(11) | NO |  | NULL |  | 
| from_date | date | YES |  | NULL |  | 
| to_date | date | YES |  | NULL |  | 
+-----------+---------+------+-----+---------+-------+ 
3 rows in set (0.01 sec) 

mysql> explain dept_manager 
    -> ; 
+-----------+---------+------+-----+---------+-------+ 
| Field  | Type | Null | Key | Default | Extra | 
+-----------+---------+------+-----+---------+-------+ 
| emp_no | int(11) | NO | PRI | NULL |  | 
| dept_no | char(4) | NO | PRI | NULL |  | 
| from_date | date | NO |  | NULL |  | 
| to_date | date | NO |  | NULL |  | 
+-----------+---------+------+-----+---------+-------+ 
4 rows in set (0.00 sec) 

mysql> explain employees; 
+------------+---------------+------+-----+---------+-------+ 
| Field  | Type   | Null | Key | Default | Extra | 
+------------+---------------+------+-----+---------+-------+ 
| emp_no  | int(11)  | NO | PRI | NULL |  | 
| birth_date | date   | NO |  | NULL |  | 
| first_name | varchar(14) | NO |  | NULL |  | 
| last_name | varchar(16) | NO |  | NULL |  | 
| gender  | enum('M','F') | NO |  | NULL |  | 
| hire_date | date   | NO |  | NULL |  | 
+------------+---------------+------+-----+---------+-------+ 
6 rows in set (0.00 sec) 

mysql> explain salaries; 
+-----------+---------+------+-----+---------+-------+ 
| Field  | Type | Null | Key | Default | Extra | 
+-----------+---------+------+-----+---------+-------+ 
| emp_no | int(11) | NO | PRI | NULL |  | 
| salary | int(11) | NO |  | NULL |  | 
| from_date | date | NO | PRI | NULL |  | 
| to_date | date | NO |  | NULL |  | 
+-----------+---------+------+-----+---------+-------+ 
4 rows in set (0.00 sec) 

mysql> explain titles; 
+-----------+-------------+------+-----+---------+-------+ 
| Field  | Type  | Null | Key | Default | Extra | 
+-----------+-------------+------+-----+---------+-------+ 
| emp_no | int(11)  | NO | PRI | NULL |  | 
| title  | varchar(50) | NO | PRI | NULL |  | 
| from_date | date  | NO | PRI | NULL |  | 
| to_date | date  | YES |  | NULL |  | 
+-----------+-------------+------+-----+---------+-------+ 
4 rows in set (0.00 sec) 

mysql> explain departments; 
+-----------+-------------+------+-----+---------+-------+ 
| Field  | Type  | Null | Key | Default | Extra | 
+-----------+-------------+------+-----+---------+-------+ 
| dept_no | char(4)  | NO | PRI | NULL |  | 
| dept_name | varchar(40) | NO | UNI | NULL |  | 
+-----------+-------------+------+-----+---------+-------+ 
2 rows in set (0.01 sec) 

mysql> explain current_dept_emp; 
+-----------+---------+------+-----+---------+-------+ 
| Field  | Type | Null | Key | Default | Extra | 
+-----------+---------+------+-----+---------+-------+ 
| emp_no | int(11) | NO |  | NULL |  | 
| dept_no | char(4) | NO |  | NULL |  | 
| from_date | date | YES |  | NULL |  | 
| to_date | date | YES |  | NULL |  | 
+-----------+---------+------+-----+---------+-------+ 
4 rows in set (0.02 sec) 

mysql> explain dept_emp; 
+-----------+---------+------+-----+---------+-------+ 
| Field  | Type | Null | Key | Default | Extra | 
+-----------+---------+------+-----+---------+-------+ 
| emp_no | int(11) | NO | PRI | NULL |  | 
| dept_no | char(4) | NO | PRI | NULL |  | 
| from_date | date | NO |  | NULL |  | 
| to_date | date | NO |  | NULL |  | 
+-----------+---------+------+-----+---------+-------+ 
4 rows in set (0.00 sec) 
+1

['EXPLAIN EXTENDED'](https://dev.mysql.com/doc/refman/5.7/en/explain-extended.html)を実行して質問に出力してください。これは、最適化が可能な場所に人々をスポットするのに役立ちます。 –

+0

これを実行すると、従業員データベースの内部で、または最初に使用するDBを選択する必要がある場所の外にこれを実行する必要がありますか? – SomeStudent

+1

ここ数十年前によく使用されていたJOIN構文に変換してみてください。それはそのようなことをはるかに明瞭にすることができます。 – Uueerdo

答えて

1

はここにあなたのクエリは21世紀JOIN構文を使用するようにリファクタリングです。

SELECT DISTINCT d.dept_name, count(e.emp_no), AVG(s.salary), 
     ROUND(YEAR(e.birth_date), -1) AS birth_date 
    FROM employees e 
    JOIN salaries s ON e.emp_no = s.emp_no 
    JOIN dept_emp de ON de.emp_no = e.emp_no 
    JOIN departments d ON de.dept_no = d.dept_no 
GROUP BY d.dept_name, ROUND(YEAR(e.birth_date), -1); 

DISTINCTが集合(GROUP BY)クエリに冗長であることに注意してください。それを取り除くことは2,3秒を削る。

salariesテーブルには過去の給与データが含まれています。各行にはfrom_dateto_dateが含まれています。 from_date列は、従業員番号とともにそのテーブルの主キーの一部です。だからあなたの質問は無差別に給料データの全部を平均し、あまりにも多くのレコードを引き出します。

このクエリには4.6秒かかります(私のマシンはあなたのものとほぼ同じ速度で、最初のクエリでは11秒かかります)。それは、ロット全体を処理するのではなく、特定の時点の給与レコードと部門所属レコードを抽出するため、与えられたデータでより意味があります。

SELECT d.dept_name, COUNT(e.emp_no), AVG(s.salary), 
     ROUND(YEAR(e.birth_date), -1) AS birth_date 
    FROM employees e 
    JOIN salaries s ON e.emp_no = s.emp_no 
    JOIN dept_emp de ON de.emp_no = e.emp_no 
    JOIN departments d ON de.dept_no = d.dept_no 
WHERE s.from_date<='2014-01-01' AND s.to_date >'2014-01-01' 
    AND de.from_date<='2014-01-01' AND de.to_date >'2014-01-01' 
GROUP BY d.dept_name, ROUND(YEAR(e.birth_date), -1); 

これは25万の従業員レコードを処理しているため、1ミリ秒あたり52レコードを処理しています。ノートパソコンには悪くない。

+0

ご覧いただきありがとうございます。私はまだ主キーを適切に活用する方法について学ぶことがたくさんあります。私は多少近づいていたと思いますが、私はそれを修正しようとしたときに同様の結合構文を持っていました。おそらくジョインを行うことでパフォーマンスの向上を否定したWHERE節は省略しましたが。 – SomeStudent

関連する問題