MySQLのLEFTは、使用してJOINまたは非常に遅いです

noother:

テーブルのユーザーは約80,000レコードを持っています

テーブルの友人900,000についての記録を持っています

FIRSTNAME =「ヴェレーナ」が104件のレコードがあります。

このクエリ非常に遅い(> 20秒)される(その非常に単純化しているため、クエリのポイントがなくなっています):

SELECT users.id FROM users
LEFT JOIN friends ON (
    users.id = friends.user_id OR
    users.id = friends.friend_id
)
WHERE users.firstname = 'verena';

私は削除または結合内の場合は、クエリはとてもいずれかの瞬間には、次のとおりです。

SELECT users.id FROM users
LEFT JOIN friends ON (
    users.id = friends.user_id
)
WHERE users.firstname = 'verena';

1487の結果を返しますか、

SELECT users.id FROM users
LEFT JOIN friends ON (
    users.id = friends.friend_id
)
WHERE users.firstname = 'verena';

帰国2849件の結果が即座に実行(0.001s)

私は他のすべてを削除し、まっすぐに行く場合

SELECT 1 FROM friends WHERE user_id = xxx OR friend_id = xxx

若しくは

SELECT id FROM users WHERE firstname = 'verena';

これらのクエリも一瞬です。

friends.friend_idのインデックスは、friends.user_idとusers.firstnameが設定されています。

手動でそれを離れて取って、すべてが速く燃える単離する文を実行する場合は、トップクエリが遅い中で、なぜ私は理解していません。

私の唯一の疑いは今MariaDBは最初の友人を持つすべてのユーザーが参加し、唯一のファーストネームは「ヴェレーナを」= WHEREのためにそのフィルタの後、代わりに最初のフィルタリングの望ましい動作のファーストネーム=「ヴェレーナ」のため、その後、友人のテーブルと結果を結合していることですOR内の削除条件が速いことになるだろう、JOINなぜ、それでも、私は表示されません。

私は1つがガレラクラスタなしMariaDB 10.4.12とガレラクラスタと1とMariaDB 10.3.22を実行し、2台の異なるマシン上でこれをテストしました

トップクエリは、このような巨大な減速をしているとどのように私は、いくつかの文にSQLを分割することなく、これを修正なぜ技術的な理由は何ですか?

編集:ここでは正しくBarmarさんのコメントで述べたように、それはすべてのレコードを友人テーブルやスキャンのために任意のインデックスを使用していない言って、それのためにEXPLAIN出力は次のようになります。

+------+-------------+---------+------+-------------------+-----------+---------+-------+--------+------------------------------------------------+
| id   | select_type | table   | type | possible_keys     | key       | key_len | ref   | rows   | Extra                                          |
+------+-------------+---------+------+-------------------+-----------+---------+-------+--------+------------------------------------------------+
|    1 | SIMPLE      | users   | ref  | firstname         | firstname | 768     | const | 104    | Using where; Using index                       |
|    1 | SIMPLE      | friends | ALL  | user_id,friend_id | NULL      | NULL    | NULL  | 902853 | Range checked for each record (index map: 0x6) |
+------+-------------+---------+------+-------------------+-----------+---------+-------+--------+------------------------------------------------+

SQLは、両方の索引を使用するか、私はちょうど例Barmarの提案のために使用して、その周りにこの制限と仕事を受け入れなければならないようにする方法はありますか?

Barmar:

MySQLは通常、使用時にインデックスを使用することができませんOR別の列に参加すること。それだけで、それが使用さそうだとすれば、参加してテーブルごとに一つのインデックスを使用することができfriends.user_id、インデックスを、それは使用しませんfriends.friend_idし、その逆。

解決策は2つの高速のクエリを実行し、それらを組み合わせることですUNION

SELECT users.id FROM users
LEFT JOIN friends ON (
    users.id = friends.user_id
)
WHERE users.firstname = 'verena';
UNION
SELECT users.id FROM users
LEFT JOIN friends ON (
    users.id = friends.friend_id
)
WHERE users.firstname = 'verena';

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=320530&siteId=1