3

かなりの数のレコードを含むデータベースがあり、ユーザー アイテムが保存されていないユーザーを見つけたいと考えています。

select `name`
  from `users`
 where `ID` not in (select distinct `userID` from `userItem`)

このクエリは、MySQL サーバーによって切断される前に実行を終了することさえできません。ここには、私が知らない大きな非効率性がありますか?

には 200,000 レコード、userItemには 14,000 レコードがありusersます。

クエリの Explain の結果:

1   PRIMARY users   ALL NULL    NULL    NULL    NULL    13369   Using where
2   DEPENDENT SUBQUERY  userItem    index   NULL    userID  8   NULL    189861  Using where; Using index; Using temporary
4

4 に答える 4

5
  1. userItem.userID と user.ID はインデックス化されていますか? いいえの場合は、それらを追加します。
  2. MySQL JOIN 句では、より高速になる場合があります。

例えば ​​-

SELECT name
  FROM users u
  LEFT JOIN userItem ui
    ON ui.userID = u.ID
  WHERE ui.userID IS NULL
于 2012-10-04T13:51:54.043 に答える
2

あなたの質問は「なぜ」とても遅いです。その理由は、MySQL がすべての行に対してサブクエリを再実行するためです。サブクエリを一度実行してから終了すると思うでしょう。しかし、いいえ、それは無数に再実行されます。

最速の代替手段は、@Parado のわずかなバリエーションだと思います。

select `name`
  from `users` u
 where not exists (select 1 from userItem ui where ui.userID = u.id limit 1)

これは、ui.UserId のインデックスと組み合わせて使用​​する必要があります。

于 2012-10-04T14:00:16.063 に答える
0

多分not existsもっと速くなるでしょう:

select `name`
  from `users` u
 where not exists
 (select 1 
  from `userItem` ui 
  where ui.userID=u.id)
于 2012-10-04T13:47:40.503 に答える
0

ユーザー(ID)と(ユーザーID)のユーザーアイテムに一意のインデックスを作成します。

Ex . SELECT DISTINCT a, b, c FROM t1 WHERE NOT EXISTS (SELECT NULL FROM t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c)

1つのキーのみをチェックする場合でも、NOTINを使用することはこれを行うための最良の方法ではありません。その理由は、NOT EXISTSを使用する場合、DBMSは必要な列にインデックスが存在する場合にのみインデックスをチェックする必要があるためです。一方、NOT INの場合は、実際のデータを読み取り、後でチェックする必要がある完全な結果セットを作成する必要があります。 。

LEFT JOINを使用してからNULLをチェックすることも悪い考えです。クエリが両方のテーブルを完全に読み取り、その後多くを破棄する必要があるため、テーブルが大きい場合は非常に遅くなります。また、列でNULL値が許可されている場合、NULLをチェックすると誤検知が報告されます。

于 2012-10-04T13:54:09.403 に答える