ブログ記事 Joins versus Subqueries: Which Is Faster?では、結合はサブクエリよりも高速に実行される傾向があることを学びました。そうは言っても、これは普遍的なルールではないため、結合が望ましいと自動的に想定したくない場合があります。その記事で述べたように、クエリに多くの結合を追加する必要がある場合、データベースサーバーはより多くの作業を行う必要があり、データの取得時間が遅くなる可能性があります。この記事では、結合を使用するクエリとサブクエリを含むクエリを比較するために実行できるいくつかの簡単なテストを紹介し、どちらが最適かを選択できるようにします。
2つのクエリ、同じ結果
ほとんどの場合、クエリは結合またはサブクエリを使用して記述できます。説明のために、MySQL Sakila Sample Databaseから国とそれに関連付けられた都市と住所を共に選択するクエリを示します。最初のSELECTステートメントは結合を使用し、2番目のステートメントはサブクエリを使用してまったく同じデータをフェッチします:
SELECT co.Country, COUNT(DISTINCT ci.city_id) AS city_cnt, COUNT(a.city_id) AS address_cnt FROM country co INNER JOIN city ci ON co.country_id = ci.country_id INNER JOIN address a ON ci.city_id = a.city_id GROUP BY co.country_id; SELECT Co.Country, (Select COUNT(1) FROM City Ci WHERE Ci.country_id=co.country_id) AS city_cnt, (Select COUNT(1) FROM Address A INNER JOIN city c on a.city_id=c.city_id WHERE C.country_id=co.country_id) AS address_cnt From Country Co;
クエリを同時に実行できるため、結果を簡単に比較できます。それぞれの結果セットは、SQLエディタの下のそれぞれのタブに表示されます。以下の画像では、結果2タブの内容が結果1横に表示されており、簡単に比較できます:
クエリ実行時間
両方のステートメントが同等であることを確認したので、実行時間を比較しましょう。
これを行うためには、個々のステートメントを選択して、実行ボタンをクリックします。そのラベルは、エディタでテキストが選択される度に、選択部分を実行に変わります。画面の下部に0.020sの経過時間が表示されます。
2番目のステートメントで同じことを行うと、経過時間は0.021sになります。わずかな違いですが、データの量が増えると大きくなります:
実行計画の比較
クエリの実行計画は、実行速度に関する多くの情報を明らかにすることができます。Navicatでは、説明ボタンをクリックして実行計画を表示できます。説明の結果を解釈できるようになるためにはある程度の練習が必要ですが、そうすることでクエリの効率を確認しようとする際に利益を得ることができます。
説明1タブには、最初の(結合)クエリの実行計画が表示されます。3つのSIMPLE選択が含まれていることが一目でわかります。
一方、説明2タブには、1つのPRIMARY選択がリストされ、その後に3つのDEPENDENT SUBQUERYが続きます。深く掘り下げなくても、2番目の(サブクエリ)ステートメントを実行するために必要な追加の手順があることが既にわかります。
結論
このブログは、Joins versus Subqueries: Which Is Faster?の記事で到達した結論を確認しているように見えますが、結合とサブクエリの両方のアプローチを比較することは価値のある演習になる可能性があります。いずれにせよ、その場で集計値を計算し、それを外部クエリで比較のために使用する必要がある場合など、サブクエリが結合よりも有利な時が今でもあります。