2011-03-28 37 views
35

私の質問に先だって、私はこのようなものを直接サポートしていないことを理解しています。私が探しているのは、私に半分の尊敬の念を抱かせるような回避策や派生した派生物です。MySQLの長いクエリの進行状況の監視

私は、クラスタエンジンを使用してかなり大きなMySQLクラスタ(テーブル> 4億行以上)を使用しています。

は道を知って、誰もがいずれかの MySQLでの長いクエリを通じて進歩の正確な表示を直接を取得するか、そうでない場合は(良いか)いくぶんを導出することですか?私は45分かかる可能性のあるクエリをいくつか持っており、私たちが10%か90%かどうかを判断する必要があります。

EDIT:

ここでコメントで要求されるように、私の元の質問につながっているクエリのの蒸留と総称化バージョンです...

SELECT `userId` 
FROM `openEndedResponses` AS `oe` 
WHERE 
    `oe`.`questionId` = 3 -- zip code 
    AND (REPLACE(REPLACE(`oe`.`value`, ' ', ''), '-', '') IN ('30071', '30106', '30122', '30134', '30135', '30168', '30180', '30185', '30187', '30317', '30004')); 

このクエリ9500万行の単一の表に対して実行されます。クエリの実行には8秒、データの転送には13秒(合計21秒)かかります。テーブルのサイズと、使用されている文字列操作関数があることを考えると、かなり速く走っていると言えます。しかし、ユーザーには、まだ21秒間停止またはアイドル状態のままです。進行状況を示す指標が理想的です。

+0

1回のクエリで最大45分かかりますか、それとも小さなINSERT/UPDATE/DELETEクエリですか? –

+0

ただ1つのクエリ。 – KOGI

+0

KOGI、あなたがあなたの問題を解決できたら、それを答えとして加えるべきです。 –

答えて

1

今のところ私の非常に特殊な状況のために、このための実際の解決策はないようです。クエリをいくつかの小さなものに分割することができず、最初にselect count(*)に逆効果があることを証明してから、実際のクエリを実行しています(既に痛々しく遅いクエリの実行時間を2倍にします)。まもなく、MySQLはこのようなものをサポートします

+0

なぜあなたは 'count(*)'を選択しますか? –

+0

これは本当に古いものですが、 'COUNT(*)'は複数の小さなクエリにクエリをチャンクするためにいくつの行があるかを判断する方法でした。 – KOGI

7

処理する行数を照会し、処理をループに分割して一度に合計行のサブセットのみを処理することで、このような見積もりができました。

フルループはかなり関与していたが、基本的なロジックは次のように行ってきました:IDが均等に分散されている場合、これは最高の作品

SELECT @minID = Min(keyColumn) FROM table WHERE condition 
SELECT @maxID = Max(keyColumn) FROM table WHERE condition 
SELECT @potentialRows = (@maxID - @minID)/@iterations 

WHILE @minID < @maxID 
BEGIN 
    SET @breakID = @minID + @potentialRows 
    SELECT columns FROM table WITH (NOLOCK, ...) 
    WHERE condition AND keyColumn BETWEEN @minID AND @breakID 

    SET @minID = @breakID + 1 
END 

注意。

+0

一度クエリを実行してminIdを取得し、もう一度maxIdを実行してから3回目(複数のチャンクサブクエリで構成される)を実行します。これは間違いなく進捗の示唆を提供しますが、それは効果的に合計クエリ時間を3倍にします(最小値と最大値の決定を1つのクエリに組み合わせると、少なくとも2倍になります)。私は何が欠けていますか? – KOGI

+1

@KOGI:MIN/MAX値を計算している列が索引付けされている場合、CEIL(LOG2(rows))のような行を調べる必要があります。その列が索引付けされていない場合は、SELECTがそれを基にしている場合には、おそらくテーブルが巨大なので、その索引を追加するためにダウンタイムを食べなければならないでしょう... –

+0

Thanks、目立つコンパイラ。私はこのアイデアが好きで、今のところ私が見てきた最良の選択肢です。私はいくつかのチャンクされたクエリを1つの大きなクエリに対して実行するパフォーマンスの影響が(MIN/MAXの決定を無視して)どうなるのだろうか... – KOGI

2

私は、MySQLが、私は、MySQLは、実行中のクエリの進行状況に関するあらゆる表示をサポートしていないと確信しているをサポートしていることはないと思います。唯一の解決策は、クエリを最適化/分割することです。 Dour High Archが示唆しているように、SelectをIDで分割することができます。ここに33万円の行テーブルからのクエリがあります。

mysql> SELECT SQL_NO_CACHE min(id), max(id) FROM `urls`; 
+---------+----------+ 
| min(id) | max(id) | 
+---------+----------+ 
| 5000 | 35469678 | 
+---------+----------+ 
1 row in set (0.00 sec) 

分割するには少なくとも整数の整数を使用することをお勧めします。 プライマリまたはユニークインデックスであり、null値を許可しないでください。

+1

+1解決策としてこれらの回答のいずれかを受け入れることはできませんが、アイディアと努力はまだ評価されています!ありがとう! – KOGI

2

複雑なクエリの場合は、EXPLAIN SQLコマンドまたはMySQLクエリアナライザが何が起きているのかを理解するのに役立ちます。単なる大規模なクエリの場合は、SELECT INTOを使用して一時テーブルを作成したり、SELECTクエリでLIMIT/OFFSET句を使用したりすることもできます。元のテーブルでLIMIT/OFFSETを使用する場合は、トランザクションレベルを直列化可能なIIRCに設定する必要があるため、データの反復処理中に一貫性のある読み取りを行う必要があります。最初にテンポラリ・テーブルを作成する場合、そのテーブルは一貫性を保つ必要があります。

+0

+1解決策としてこれらの回答のいずれかを受け入れることはできませんが、アイデアと努力はまだ評価されています!ありがとう! – KOGI

0

読み込み/書き込みの負荷を分散できるようにmysqlテーブルを分割する方法を見てみましょう。 (ハードウェアに明らかに依存して)50万行

+0

提案していただきありがとうございます。これは間違いなくクエリ自体を高速化する可能性がありますが、速度に関係なく、私が探していたのは進捗を監視する方法でした。 – KOGI

+0

Ar!今、私はあなたの質問を読んでいます。悪い考えがあります。それは仕事への途中で迅速な応答でした:) – Christian

+1

あなたのテーブルをパーティションに分割し、可能であれば別々のテーブルに分割すると、あなたのクエリがすばやく実行できるようになりました。監視することを心配する必要はありません。私たちは、あなたが実行する必要がある列と読み書き機能を与えれば、より速く実行するようにテーブルを分割、索引付けする方法を調べることができます。 – Christian

1

に各パーティションを制限しようとしているを見てくださいと、ここでは、次のクエリを改善するために行う必要がありますものです:

SELECT `userId` 
FROM `openEndedResponses` AS `oe` 
WHERE 
    `oe`.`questionId` = 3 -- zip code 
    AND (REPLACE(REPLACE(`oe`.`value`, ' ', ''), '-', '') IN ('30071', '30106', '30122', '30134', '30135', '30168', '30180', '30185', '30187', '30317', '30004')); 

あなたはOEを確保する必要があります.questionIdは索引付けされます。 oe.questionIdが3の場合、oe.valueに表全体にスペースがないことを確認する必要があります。 4または5が市区町村の名前であるとすれば、あなたはまだスペースを許可したいと思っています。

これを行うと、すべての置換が削除され、MySQLはoe.valueでインデックスを使用できます。

MySQLは両方のインデックスをマージし、処理の面ではるかに高速に結果を得ます。

多くのユーザーIDが繰り返し使用されている場合は、それらをグループ化したいと思うでしょう。インデックスからのエントリがすぐに破棄されるようにします。マージされたインデックス全体をスキャンする必要があります。結果セットのサイズは転送に要する時間が短くなります。はるかに少ない13秒!

結果を投稿してください。

ベスト!

+0

提案していただきありがとうございます。この質問は本当に古いものですが、クエリー自体のスピードアップにつながる可能性があります。しかし、スピードに関係なく、私が探していたのは進歩を監視する方法でした。高速ではなく、それ以上の最適化もできないクエリがいくつかあります。実行されたクエリの実行状況を確認する方法が必要でした。 – KOGI

1

これは古い質問ですが、私のアップデートが250m行のクエリにどれくらいの時間を要するかを把握しようとすると、同様の答えを探していました。

あなたが実行している場合:

SHOW ENGINE INNODB STATUS \G 

次に取引の下で、このセクションを調べ、問題の取引を見つける:

---TRANSACTION 34282360, ACTIVE 71195 sec starting index read 
mysql tables in use 2, locked 2 
1985355 lock struct(s), heap size 203333840, 255691088 row lock(s), undo log entries 21355084 

重要なビットは、 "ログエントリを元に戻す" です。更新された行ごとに、私のケースでは、UNDOログエントリを追加するように見えました(数秒後にもう一度実行して、追加されたエントリの数を確認しようとしました)。

あなたはステータスレポートの最後までスキップする場合は、この表示されます:あなたがしている場合、我々はスピードのアップデートが適用されていることを見ることができます。ここ

Number of rows inserted 606188224, updated 251615579, deleted 1667, read 54873415652 
0.00 inserts/s, 1595.44 updates/s, 0.00 deletes/s, 3190.88 reads/s 

は(が、毎秒1595.44行です他の更新クエリを並行して実行すると、この速度はクエリ間で分離される可能性があります)。

だから、私は21mが(250m-21m)229mの行を残して更新されていることを知っています。だから、私は日の別のカップルのための私の親指をひねりでき

を行くために (143125/60)/ 60 = 39.76時間に行く

2.29億/ 1600 = 143125秒で表示されます。この答えが間違っていない限り、その前にいつか私はそれを更新します!

+0

ああ、私はちょうどこれを騒がしていると思う、何らかの理由で、これはアップデートに関するものだと思っていました。 – user7253130

関連する問題