2

クエリの目的:

地区ごとにレースを表示します。

クエリ:

SELECT school_data_schools_outer.district_id, 
       school_data_race_ethnicity_raw_outer.year,  
       school_data_race_ethnicity_raw_outer.race,
       ROUND( 
           SUM( school_data_race_ethnicity_raw_outer.count) /
                (SELECT SUM(count)
                   FROM school_data_race_ethnicity_raw as school_data_race_ethnicity_raw_inner
             INNER JOIN school_data_schools as school_data_schools_inner 
                  USING (school_id)
                  WHERE school_data_schools_outer.district_id = school_data_schools_inner.district_id 
                    AND school_data_race_ethnicity_raw_outer.year = school_data_race_ethnicity_raw_inner.year) * 100, 2)
      FROM school_data_race_ethnicity_raw as school_data_race_ethnicity_raw_outer
INNER JOIN school_data_schools as school_data_schools_outer USING (school_id)
  GROUP BY school_data_schools_outer.district_id, 
           school_data_race_ethnicity_raw_outer.year, 
           school_data_race_ethnicity_raw_outer.race

mysql> explain SELECT school_data_schools_outer.district_id, school_data_race_ethnicity_raw_outer.year, school_data_race_ethnicity_raw_outer.race,ROUND(SUM(school_data_race_ethnicity_raw_outer.count)/( SELECT SUM(count) FROM school_data_race_ethnicity_raw as school_data_race_ethnicity_raw_inner INNER JOIN school_data_schools as school_data_schools_inner USING (school_id) WHERE school_data_schools_outer.district_id = school_data_schools_inner.district_id and school_data_race_ethnicity_raw_outer.year = school_data_race_ethnicity_raw_inner.year ) * 100,2) FROM school_data_race_ethnicity_raw as school_data_race_ethnicity_raw_outer INNER JOIN school_data_schools as school_data_schools_outer USING (school_id) GROUP BY school_data_schools_outer.district_id, school_data_race_ethnicity_raw_outer.year, school_data_race_ethnicity_raw_outer.race;
+----+--------------------+--------------------------------------+--------+----------------------------+---------+---------+----------------------------------------------------------------------+-------+---------------------------------+
| id | select_type        | table                                | type   | possible_keys              | key     | key_len | ref                                                                  | rows  | Extra                           |
+----+--------------------+--------------------------------------+--------+----------------------------+---------+---------+----------------------------------------------------------------------+-------+---------------------------------+
|  1 | PRIMARY            | school_data_race_ethnicity_raw_outer | ALL    | school_id,school_id_2      | NULL    | NULL    | NULL                                                                 | 84012 | Using temporary; Using filesort |
|  1 | PRIMARY            | school_data_schools_outer            | eq_ref | PRIMARY                    | PRIMARY | 257     | rocdocs_main_drupal_7.school_data_race_ethnicity_raw_outer.school_id |     1 |                                 |
|  2 | DEPENDENT SUBQUERY | school_data_race_ethnicity_raw_inner | ref    | school_id,year,school_id_2 | year    | 4       | func                                                                 |  8402 |                                 |
|  2 | DEPENDENT SUBQUERY | school_data_schools_inner            | eq_ref | PRIMARY                    | PRIMARY | 257     | rocdocs_main_drupal_7.school_data_race_ethnicity_raw_inner.school_id |     1 | Using where                     |
+----+--------------------+--------------------------------------+--------+----------------------------+---------+---------+----------------------------------------------------------------------+-------+---------------------------------+
4 rows in set (0.00 sec)

mysql>

mysql> describe school_data_race_ethnicity_raw;
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| school_id | varchar(255) | NO   | MUL | NULL    |                |
| year      | int(11)      | NO   | MUL | NULL    |                |
| race      | varchar(255) | NO   |     | NULL    |                |
| count     | int(11)      | NO   |     | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)

mysql> describe school_data_schools;
+-------------+----------------+------+-----+---------+-------+
| Field       | Type           | Null | Key | Default | Extra |
+-------------+----------------+------+-----+---------+-------+
| school_id   | varchar(255)   | NO   | PRI | NULL    |       |
| grade_level | varchar(255)   | NO   |     | NULL    |       |
| district_id | varchar(255)   | NO   |     | NULL    |       |
| school_name | varchar(255)   | NO   |     | NULL    |       |
| address     | varchar(255)   | NO   |     | NULL    |       |
| city        | varchar(255)   | NO   |     | NULL    |       |
| lat         | decimal(20,10) | NO   |     | NULL    |       |
| lon         | decimal(20,10) | NO   |     | NULL    |       |
+-------------+----------------+------+-----+---------+-------+
8 rows in set (0.00 sec)

注:私も試しました:

select sds.school_id, 
  detail.year, 
  detail.race,
  ROUND((detail.count / summary.total) * 100 ,2) as percent 
FROM school_data_race_ethnicity_raw as detail
inner join school_data_schools as sds USING (school_id)
inner join (
  select sds2.district_id, year, sum(count) as total
  from school_data_race_ethnicity_raw
  inner join school_data_schools as sds2 USING (school_id)
  group by sds2.district_id, year
  ) as summary on summary.district_id = sds.district_id 
    and summary.year = detail.year
4

2 に答える 2

0

これは遅いためです:

  1. school_data_race_ethnicity_raw_outer で使用中のインデックスがないため、約 84,000 行のそれぞれをスキャンしています
  2. 相関サブクエリを使用しているため、複雑な計算を行ごとに 1 回、つまり 84,000 回実行する必要があります。

最良のアプローチは、相関サブクエリを使用しないことですが、そうでない場合は、高速化するために、その内部クエリ全体 (および独自のインデックスを介した他の部分) を雷で実行できるように、カバー インデックスを使用する必要があります。インデックスのみを使用して高速化します。インデックスに関する優れたチュートリアルについては、こちらをご覧ください。それは私に多くのことを教えてくれました!現在、内部クエリは school_data_race_ethnicity_raw の year インデックスのみを使用しているため、84000 回の計算ごとに 8000 行を読み取って、残りの必要なものを検索する必要があります。インデックスを使用すると、これがはるかに高速になります。たとえば、school_data_race_ethnicity_raw に複合インデックスを作成すると、次のように役立つことがわかります。

CREATE index inner_composite ON school_data_race_ethnicity_raw (year, district_id, schoolid, count)

これにより、WHERE で使用されるすべてのフィールドをインデックスから取得し、次に結合フィールド、次に選択するフィールドを取得できます。説明結果の「キー」列に表示されるはずです。また、うまくいけば、一番右の列に 'using index' が表示され、テーブル アクセスが発生していないことが示されます。これは桁違いに高速です。

クエリが言及する列に大量のインデックスを追加して、キー列で何が取得されるかを確認することで、簡単なスタイルを試すことができます。何かが表示された場合は、クエリを読んでそのテーブルの他の列が使用されていることを確認し、それらの列が右側に追加された新しいインデックスを追加して、それがより適切に機能するかどうかを確認します。何が機能するかがわかったら、未使用のインデックスを忘れずに削除してください。

MySQL では、列の SUM を直接インデックス化することはできません。これが最速の方法です。そのため、別の DB に移動したい場合を除き (可能であれば良い考えです)、これは常に少し遅くなります。

于 2012-09-06T22:11:38.167 に答える
-1

地区ごとのレース数を取得するためにデータを集計する必要があるのはこれだけです。目標を達成するのに不要であり、いくつかのクレイジーなサブクエリを強制しているため、元のデータで多くの計算を行っている理由がわかりません。

SELECT SUM(students.count) as studentCount, School.district_id, students.race
FROM school_data_schools schools, 
school_data_race_ethnicity_raw students
WHERE shools.school_id = students.school_id
GROUP BY district_id, race

おそらく、school_data_race_ethnicity_raw.school_id のインデックスも必要です (複数列キーの一部としてではなく、単独で)

EDITは、OPが合計だけでなくパーセンテージの内訳を探していることを認識していませんでした

SELECT ((studentCount / districtTotal) * 100) as percentage, district_id, race

FROM(

SELECT SUM(students.count) as studentCount, Schools.district_id, students.race,
  (SELECT SUM(inStudents.count)
   FROM school_data_schools inSchools, 
    school_data_race_ethnicity_raw inStudents
   WHERE inSchools.school_id = inStudents.school_id
   AND inSchools.district_ID = Schools.district_id
   GROUP BY inSchools.district_id) as districtTotal

    FROM school_data_schools schools, 
    school_data_race_ethnicity_raw students

WHERE schools.school_id = students.school_id
GROUP BY district_id, race
) table1

これは非常に迅速に実行されますが、複数列インデックスの一部ではない school_data_race_ethnicity_raw.school_id にインデックスがあることを確認する必要があります。ここで実際の動作を見ることができます。私のテストケースはかなり小さいですが、チェックアウトしているようです。

于 2012-09-06T00:16:23.427 に答える