3

MySQL 5.1.34サーバーでは、次のような厄介な状況が発生します。

mysql> explain select * FROM master.ObjectValue WHERE id IN ( SELECT id FROM backup.ObjectValue ) AND timestamp < '2008-04-26 11:21:59';
+----+--------------------+-------------+-----------------+-------------------------------------------------------------+------------------------------------+---------+------+--------+-------------+
| id | select_type        | table       | type            | possible_keys                                               | key                                | key_len | ref  | rows   | Extra       |
+----+--------------------+-------------+-----------------+-------------------------------------------------------------+------------------------------------+---------+------+--------+-------------+
|  1 | PRIMARY            | ObjectValue | range           | IX_ObjectValue_Timestamp,IX_ObjectValue_Timestamp_EventName | IX_ObjectValue_Timestamp_EventName | 9       | NULL | 541944 | Using where | 
|  2 | DEPENDENT SUBQUERY | ObjectValue | unique_subquery | PRIMARY                                                     | PRIMARY                            | 4       | func |      1 | Using index | 
+----+--------------------+-------------+-----------------+-------------------------------------------------------------+------------------------------------+---------+------+--------+-------------+
2 rows in set (0.00 sec)

mysql> select * FROM master.ObjectValue WHERE id IN ( SELECT id FROM backup.ObjectValue ) AND timestamp < '2008-04-26 11:21:59';
Empty set (2 min 48.79 sec)

mysql> select count(*) FROM master.ObjectValue;
+----------+
| count(*) |
+----------+
| 35928440 |
+----------+
1 row in set (2 min 18.96 sec)
  • すべてのレコードにアクセスするのに2分しかかからないのに、500000レコードを調べるのに3分かかるのはどうしてですか?
  • 別のデータベースのサブクエリを依存に分類するにはどうすればよいですか?
  • このクエリを高速化するにはどうすればよいですか?

アップデート:

長い時間がかかった実際のクエリはDELETEでしたが、それらについて説明することはできません。DELETEは私が副選択を使用した理由です。ドキュメントを読み、構文「DELETE FROMtUSING...」について調べました。クエリを次の場所から書き直します。

DELETE FROM master.ObjectValue 
WHERE timestamp < '2008-06-26 11:21:59' 
AND id IN ( SELECT id FROM backup.ObjectValue ) ;

の中へ:

DELETE FROM m 
USING master.ObjectValue m INNER JOIN backup.ObjectValue b ON m.id = b.id 
WHERE m.timestamp < '2008-04-26 11:21:59';

空のbackup.ObjectValueの時間を分から.01秒に短縮しました。

良いアドバイスをありがとうございました。

4

4 に答える 4

5

依存サブクエリは、外部クエリをクロールまで遅くします(これは、調べているデータセットで見つかった行ごとに1回実行されることを意味していることを知っていると思います)。

そこでサブクエリは必要ありません。サブクエリを使用しないと、クエリが大幅に高速化されます。

SELECT m.*
FROM master.ObjectValue m
JOIN backup.ObjectValue USING (id)
WHERE m.timestamp < '2008-06-26 11:21:59'

MySQLは、サブクエリが依存していない場合でも、依存しているものとして扱うことがよくあります。その正確な理由を私は本当に理解していません-おそらくそれは、クエリオプティマイザがそれを独立していると認識できないためです。FROMこれらの場合、事実上いつでも条項に移動して修正できるため、詳細をわざわざ調べることはありませんでした。

例えば:

DELETE FROM m WHERE m.rid IN (SELECT id FROM r WHERE r.xid = 10)
// vs
DELETE m FROM m WHERE m.rid IN (SELECT id FROM r WHERE r.xid = 10)

前者は依存サブクエリを生成し、非常に遅くなる可能性があります。後者は、オプティマイザにサブクエリを分離するように指示します。これにより、テーブルスキャンが回避され、クエリの実行が大幅に高速化されます。

于 2012-04-26T09:56:20.607 に答える
3

すべてのレコードにアクセスするのに2分しかかからないのに、500000レコードを調べるのに3分かかるのはどうしてですか?

COUNT(*)COUNT(1)MySQLでは常にに変換されます。したがって、各レコードを入力する必要はありません。また、メモリ内のインデックスを使用して処理を高速化すると思います。また、実行時間の長いクエリでは、範囲(<)とIN演算子を使用するため、アクセスするレコードごとに、特にサブクエリを依存として認識するため、追加の作業を行う必要があります。

別のデータベースのサブクエリを依存に分類するにはどうすればよいですか?

それが別のデータベースにあるかどうかは関係ありません。サブクエリは、外部クエリの値に依存している場合は依存していますが、これはあなたの場合でも実行できます...しかし、そうではないので、従属サブクエリとして分類されるのは確かに奇妙です。たぶんそれはMySQLの単なるバグであり、それが非常に時間がかかる理由です-外部クエリによって選択されたすべてのレコードに対して内部クエリを実行します。

このクエリを高速化するにはどうすればよいですか?

まず、JOIN代わりに次を使用してみてください。

SELECT master.*
FROM master.ObjectValue master
JOIN backup.ObjectValue backup
  ON master.id = backup.id
  AND master.timestamp < '2008-04-26 11:21:59';
于 2012-04-26T09:56:32.267 に答える
3

サブクエリの行が1つしかないことを示していることに注意してください。明らかに1行以上あります。これは、mysqlが一度に1行しかロードしていないことを示しています。mysqlがおそらく行おうとしているのは、サブクエリを「最適化」して、従属サブクエリであるマスタークエリにも存在するサブクエリのレコードのみをロードするようにすることです。これが結合の仕組みですが、クエリの表現方法によって、結合の最適化されたロジックが強制的に逆になります。

バックアップテーブル(サブクエリ)をロードし、それをマスターテーブル "timestamp<'2008-04-2611:21:59'"のフィルタリングされた結果と照合するようにmysqlに指示しました。Mysqlは、バックアップテーブル全体をロードすることはおそらく良い考えではないと判断しました。そのため、mysqlはマスターのフィルタリングされた結果を使用してバックアップクエリをフィルタリングすることを決定しましたが、サブクエリをフィルタリングしようとしたときにマスタークエリはまだ完了していません。したがって、マスタークエリから各レコードをロードするときにチェックする必要があります。したがって、依存サブクエリ。

他の人が言ったように、結合を使用してください、それは行く正しい方法です。群衆に加わってください。

于 2012-04-26T10:26:32.713 に答える
0

本当の答えは、MySQLを使用しないでください。そのオプティマイザーはごみです。Postgresに切り替えると、長期的には時間を節約できます。

「JOINを使用する」と言っているすべての人にとって、これは、このひどく恐ろしいバグの修正を10年間拒否してきたMySQLの群衆によって永続化されたナンセンスです。

于 2012-09-06T09:00:43.163 に答える