2012-04-26 3 views
3

、私は以下の困惑の状況があります。mysqlはこのサブクエリが依存していると判断するのはなぜですか? 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分かかることがありますか?
  • 別のデータベース のサブクエリはどのようにして分類できますか?
  • この質問に対しては、何ができるのですか?

UPDATE:

長い時間がかかった実際のクエリは、DELETEだったが、あなたはそれらに説明することができません。 DELETEは私が副選択を使用した理由です。

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

分から0.01までの時間を短縮
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'; 

私は今からの問合せをリライト「...使用したTからDELETE」マニュアルを読み、構文について見出しました空のバックアップの秒数.ObjectValue。

ありがとうございました。

+0

カウント(*)ははるかに速くなければなりません。 ObjectValueはテーブルかビューですか? – Johan

答えて

3

お知らせそれはサブクエリのための唯一の1行があると言いますか?明らかに1行以上あります。これは、mysqlが一度に1行しかロードしていないことを示しています。 mysqlがやろうとしていることは、サブクエリを「最適化」することで、サブクエリのレコードだけを読み込むようにすることです。これは結合の仕組みですが、クエリの表現方法によって結合の最適化された論理が逆転されました。

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

他にも言及したように、参加を使用するのは正しい方法です。群衆に参加してください。

5

従属サブクエリは外側のクエリをクロールまで遅くします(これは、参照されているデータセットに見つかった行ごとに1回実行されることを意味していると思います)。あなたは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) 

前者は依存サブクエリを生成すると非常に遅くすることができます。後者は、サブクエリを分離するようオプティマイザに指示します。サブクエリは、テーブルスキャンを回避し、クエリをより高速に実行します。

+0

バグ47914は、MySQL 5.6.5で修正されているはずです。http://bugs.mysql.com/bug.php?id=47914私は自分自身でそのバージョンを試していませんが、有望です。私はこのパフォーマンス・ヒットなしに何十年もOracleに従属していないサブ・セレクトを使用しています(アプリケーションによってはこのような問合せを書くことはほとんどありませんが、エンタープライズ内の小さなルックアップ・データ・セット'アプリケーション)。 – Jason

3

すべてのレコードにアクセスするのに2分しかかからない場合、500000レコードを調べるには3分かかることはありますか?

COUNT(*)は、常にMySQLではCOUNT(1)に変換されます。したがって、各レコードを入力する必要はなく、また、メモリ内のインデックスを使用して処理を高速化すると思います。また、長期実行クエリでは、範囲(<)と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'; 
+0

SQLは複製されたすべての列を返します(バックアップから1回、マスタから1回)。 – Romain

+0

@Romainあなたが正しいです。それを 'master。*'に変更しました。しかし、パフォーマンスに関してはそれほど重要ではないと私は思います。 –

+0

データを少なくすると、結果セットの転送が速くなり、メモリ消費も少なくなります。しかし、その影響はサブクエリを削除するよりはるかに少ないことに同意します。 – Romain

0

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

誰もが "JOINを使う"と言っているのは、この目障りに恐ろしいバグを修正するために10年間拒否したMySQLの群衆によって永続しているナンセンスだけです。

関連する問題