1

どのクエリがより速く実行され、どれが完璧なクエリですか?

SELECT
    COUNT(*) AS count
FROM
    students
WHERE
    status = 1
AND
    classes_id IN(
                    SELECT
                        id
                    FROM
                        classes
                    WHERE
                        departments_id = 1
                );

または

SELECT
    COUNT(*) AS count
FROM
    students s
LEFT JOIN
    classes c
ON
    c.id = s.classes_id
WHERE
    status = 1
AND
    c.departments_id = 1

2 つのクエリを配置しましたが、どちらも同じ結果を出力します。今、どのメソッドがより速く実行され、どのメソッドが正しい方法であるかを知りたいですか?

4

6 に答える 6

5

EXPLAINクエリの実行方法を決定するには、常に を使用する必要があります。

残念ながら、MySQL はサブクエリを DEPENDENT QUERY として実行します。これは、サブクエリが外側のクエリの各行に対して実行されることを意味します。MySQL はサブクエリが相関サブクエリではないことを検出し、それを 1 回だけ実行するほどスマートであると思われるかもしれませんが、残念ながら、それはまだそれほどスマートではありません。

そのため、MySQL は学生のすべての行をスキャンし、各行に対してサブクエリを実行し、外側のクエリでインデックスをまったく使用しません。

クエリを JOIN として記述すると、MySQL がインデックスを利用できるようになります。次のクエリは、それを記述する最適な方法です。

SELECT COUNT(*) AS count
FROMstudents s
JOIN classes c
  ON c.id = s.classes_id
  AND c.departments_id = 1
WHERE s.status = 1

これは、次のインデックスを利用します。

students(`status`)
classes(`id`, `departements_id`) : multi-column index
于 2012-05-21T15:11:07.737 に答える
3

デザインと明快さの観点から、最初のような内部選択は避けたいと思います。各クエリが最適化されるかどうか、またはどのように最適化され、どれが「より良く」実行されるかを 100% 確実にするには、使用している SQL サーバーがクエリとその計画をどのように解釈するかを確認する必要があります。Mysql では、「Explain」を使用します。

ただし....これを見なくても、私のお金はまだ結合のみのバージョンにあります...内部選択バージョンは、「IN」句内で使用する値を決定する前に、内部選択を完全に実行する必要があります--私関数で何かをラップするときにこれが真であることを知っており、IN引数としてselectを貼り付けるときにそれが真であることを確信してください。また、内部選択内のテーブルのインデックスで得られる可能性のある利点を完全に中和する良い方法であることも知っています。

私は一般的に、内部選択は非常にまれなクエリの状況でのみ本当に必要であるという意見です。通常、それらを頻繁に使用する人は、リレーショナル DB の結果セットの用語を実際には考えていない、従来の反復フロー プログラマーのように考えています...

于 2012-05-21T11:38:07.517 に答える
2

見つけるための最良の方法はそれを測定することです:

インデックスなし

  • クエリ1:0.9秒
  • クエリ2:0.9秒

インデックス付き

  • クエリ1:0.4秒
  • クエリ2:0.2秒

結論は次のとおりです。

  • インデックスがない場合は、使用するクエリに違いはありません。
  • 適切なインデックスがあれば、結合はより高速になります。
  • 正しいインデックスを追加する効果は、正しいクエリを選択する効果よりも大きくなります。パフォーマンスが重要な場合は、正しいインデックスがあることを確認してください。

もちろん、結果はMySQLのバージョンと使用しているデータの分布によって異なる場合があります。

これが私がそれをテストした方法です:

  • 1,000,000人の学生(ステータス1の25%)。
  • 50,000コース。
  • 10部門。

テストデータの作成に使用したSQLは次のとおりです。

CREATE TABLE students
(id INT PRIMARY KEY AUTO_INCREMENT,
status int NOT NULL,
classes_id int NOT NULL);

CREATE TABLE classes
(id INT PRIMARY KEY AUTO_INCREMENT,
departments_id INT NOT NULL);

CREATE TABLE numbers(id INT PRIMARY KEY AUTO_INCREMENT);

INSERT INTO numbers VALUES (),(),(),(),(),(),(),(),(),();

INSERT INTO numbers
SELECT NULL
FROM numbers AS n1
CROSS JOIN numbers AS n2
CROSS JOIN numbers AS n3
CROSS JOIN numbers AS n4
CROSS JOIN numbers AS n5
CROSS JOIN numbers AS n6;

INSERT INTO classes (departments_id)
SELECT id % 10 FROM numbers WHERE id <= 50000;

INSERT INTO students (status, classes_id)
SELECT id % 4 = 0, id % 50000 + 1 FROM numbers WHERE id <= 1000000;

SELECT COUNT(*) AS count
FROM students
WHERE status = 1
AND classes_id IN (SELECT id FROM classes WHERE departments_id = 1);

SELECT COUNT(*) AS count
FROM students s
LEFT JOIN classes c
ON c.id = s.classes_id
WHERE status = 1
AND c.departments_id = 1;

CREATE INDEX ix_students ON students(status, classes_id);
于 2012-06-13T22:40:50.780 に答える
2

EXPLAIN両方のクエリを個別に

両方のクエリの違いは、サブクエリと結合です。

ほとんどの場合、結合はサブクエリよりも高速です。Join は実行計画を作成し、処理するデータを予測するため、時間を節約できます。一方、サブクエリは、すべてのデータがロードされるまですべてのクエリを実行します。サブクエリは JOINS よりも読みやすいため、ほとんどの開発者はサブクエリを使用しますが、パフォーマンスが問題になる場合は、JOIN の方が優れたソリューションです。

于 2012-05-21T11:39:35.823 に答える
1

2 つのクエリは同じ結果を生成しません。

SELECT
    COUNT(*) AS count
FROM
    students
WHERE
    status = 1
AND
    classes_id IN(
                    SELECT
                        id
                    FROM
                        classes
                    WHERE
                        departments_id = 1
                );

...は、classes_id フィールドがあり、departments_id が 1 の classes テーブルにもある、students テーブルの行数を返します。

SELECT
    COUNT(*) AS count
FROM
    students s
LEFT JOIN
    classes c
ON
    c.id = s.classes_id
WHERE
    status = 1
AND
    c.departments_id = 1

...ステータスフィールドが1である学生テーブルの行の総数を返し、データの編成方法によってはそれ以上になる可能性があります。

クエリが同じものを返すようにする場合は、LEFT JOIN を INNER JOIN に変更して、両方の条件に一致する行のみに一致するようにする必要があります。

于 2012-06-16T20:59:08.253 に答える
0

EXPLAIN SELECT ...両方のクエリで実行し、どちらが何をするかを確認してください;)

于 2012-05-21T11:27:16.047 に答える