1

[3](おそらく重複していますが、JOINを使用した質問と解決策しか見つけることができず、それはオプションではありません。)

2つのテーブルがあります。非常に薄い(列が少ない)と非常に長い(行が多い)。1つはデータテーブル(articles)で、もう1つはACLテーブル(acl)です。

を介してアクセスできる記事のみを表示したいacl.some_id。どのサブクエリが高速ですか?

[1]
SELECT a.title
FROM articles a
WHERE 0 < (
  SELECT COUNT(1)
  FROM acl
  WHERE article_id = a.id AND some_id IN (1, 2, 3)
)

また

[2]
SELECT a.title
FROM articles a
WHERE a.id IN (
  SELECT article_id
  FROM acl WHERE some_id IN (1, 2, 3)
)

最初のサブクエリは潜在的にすべてをチェックする必要があるのに対し、そのサブクエリは一致する可能性のあるすべての行に再利用できるため、1回だけ実行されます(結果セットは非常に大きくなります)ので、私の心は2番目のものを言います一致する行。

3番目の方法がありますが、行が重複するため、これはオプションではありません(また、後で何かのためにCOUNTが必要になるため、GROUP BYは解決策ではありません(DISTINCTは解決策ではありません!)):

[3]
SELECT a.title
FROM articles a
JOIN acl
  ON acl.article_id = a.id
WHERE acl.some_id IN (1, 2, 3)

article_id XはにN回存在するためacl、その行は0-1ではなく0-N回返されます。

4番目の方法もあります:EXISTS。ypercubeに感謝します。

関連している:

4

1 に答える 1

5

とも言いますが、MySQL には少なくとも 5.5 までは、サブクエリの[2]最適化にいくつかの盲点があります。IN(新しくリリースされた) 5.6 バージョンでは、クエリ オプティマイザーがいくつか改善されています。IN(セミジョインとサブクエリ) については、MySQL ドキュメントのMySQL 5.6: Optimizing Subqueries with Semi-Join Transformations で読むことができます。

また、MariaDB (バージョン 5.3 および 5.5) のオプティマイザーにはいくつかの改善があり、一部はこの種のクエリに関連しています。ドキュメントで読むことができます: MariaDB 5.3: Semi-join subquery Optimizations

EXISTS特に 5.5 以前のバージョンを使用している場合は、次のバージョンを試すこともできます。

-- [4]
SELECT id
FROM articles AS a
WHERE EXISTS (
  SELECT *
  FROM acl 
  WHERE acl.some_id IN (1, 2, 3)
    AND acl.article_id = a.id 
) ;

ここでは、上のインデックスが役立つと思います。(article_id, some_id)または、おそらくその逆のインデックスを使用することもできます。両方を試しても問題はありません。


acl (article_id) REFERENCES article (id)信頼できる外部キーがあり、記事 ID のみが必要な場合は、1 つのテーブルからのみデータを取得することもできます。

SELECT DISTINCT article_id
FROM acl 
WHERE acl.some_id IN (1, 2, 3) ;

もちろん、サーバーにあるいくつかのバージョン、使用している (または使用する予定の) MySQL のバージョン、データ分散、およびもちろん十分なサイズのテーブルをテストする必要があります。数百行でテストしても、多くはわかりません。

于 2013-03-20T22:26:41.403 に答える