2009-07-30 7 views
2

370,000,000(3億7千万)以上の行を含むデータベースのPHPスクリプトで、次のMySQLクエリを使用しています。私はそれが非常にリソース集約的で、この1つのクエリを実行するには時間がかかることを知っています。誰も私はどのようにクエリを最適化することができるか、またはより速い別の方法で情報を取得するか知っていますか?このMySQLクエリを最適化するにはどうすればよいですか?

表情報:

games | longint, unsigned, Primary Key 
win | bit(1) 
loss | bit(1)

問合せ:あなたの助けを事前に

SELECT MID(game,{$len},1) AS move, 
     COUNT(*) AS games, 
     SUM(win) AS wins, 
     SUM(loss) AS losses 
FROM games 
WHERE game>{$something} AND game<{$something_else} 
GROUP BY move

ありがとう!私が作ることができ

+2

LIKEを数値に使用する際に非常に間違ったことがあります。MID()のグループ化と同じですが、間違っています。どうしてそれをするの? 最後に、「勝利」と「損失」の列が複数あるのではなく、「勝ち」、「損失」または「引き分け」の値を持つ「結果」列がないのはなぜですか? –

+0

LIKEか、より大きいかより小さいかのいずれかです。いずれにしても大きな違いはないとは思っていませんでした。 MID()によるグループ分けは基本的に 'ゲーム'の次の数字をグループ化します。 MID(ゲーム、1、{$ len})と同じです。勝敗はどちらかの方法で2ビットのスペースを取るので、それは問題ではありません。 – dampkwab

+0

数値にLIKEを使用すると型キャストが発生するため、効率が悪くなければなりません。勝敗の列については、1ビットだけではなく、1バイトずつ占有するのではないかと思います。 「なぜ」と尋ねるのは、おそらくもっと具体的だったはずです。実際の質問は、なぜLIKEを使用して範囲で照会してから、数値のテキスト表現を使用して結果をグループ化する必要があるかということです。あなたの "ゲーム"の列が実際に保持するデータ(実際にはbtwを記述するべきもの)はわかりませんが、あなたの問題はデータベース設計であり、効率の良いクエリではありません。 –

答えて

5

唯一の提案は、すべてのカウント、および各ゲームの合計を事前計算するためにテーブルを使用して、テーブルゲーム変更がトリガを使用する場合、それを更新することです。

+0

これは、現在使用されている数よりも数億も多くの行を必要とし、行ごとにさらに多くのスペースを必要とします。テーブルはすでにほぼ10GiBなので、それは実行可能だとは思わない。 – dampkwab

+0

しかし、あなたの主な問題は、計算が高価すぎるということです。いくらかのディスクスペースを使用して 'キャッシュ'テーブルを作成すると役立ちます。 – slipbull

+0

OK、私はキャッシュシステムのいくつかの並べ替えを構築する見てみましょうと思います。しかし、私はまだそれが取り上げられるだろうと心配しています。 – dampkwab

0

重い読書をしている場合は、一般的に照会するデータの上に集計テーブルを保持し、維持することを検討してください。

+0

残念ながら、ほぼ同じ頻度で '$ game'に異なる値を使用しています。 – dampkwab

+0

これは、あなたが必要とする$ゲームの異なる値を集計するという意味です。たとえそれが数百万に及ぶとしても、個々の記録よりもずっと少なくなるでしょう。 – nos

0

これを非正規化して「ゲーム」ごとの統計だけでなく、「移動」ごとに統計を記録する「移動」テーブルを作成するように聞こえます。

0

ストレージスペースを犠牲にすることによって「スピードを買う」ことができますが、ストレージスペースを有効にすることはできますが、パフォーマンスは低下します。あなたの問題はスピードであるので、いくつかの事前計算が必要です。そして、はい、クエリのいくつかのプロファイリング。

「大きなもの」は、OLTP(実際のトランザクションをリアルタイムで処理する)とDW(大量のデータを分析する)に異なるコンフィグ(異なるハードウェアと設定)を使用していました。

0

mid()関数はこのクエリを強制終了します。 MySQLは、mid()関数を処理するためにメモリ内に一時テーブルを作成しなければなりません。

私は$ gameがゲームの種類であると仮定しています。 (チェッカー、チェス、ティックタックつま先)

私はゲームの種類のために別のテーブルをオフにします。これにより、あなたのグループは、はるかに高速なインデックスを利用することができます。

[game] 
game bigint unsigned 
win bit 
loss bit 
game_type_id bigint unsigned 

[game_type] 
game_type_id bigint unsigned 
game_type_desc varchar(13) 

がこの大きなテーブルに変更文には注意してください:

は、私のような何かを示唆しています。 変更を発行する前に必ずバックアップを作成してください。

+0

実際、 '$ game'は15桁の5進数です。 :P また、質問で言うように、MID()は5つの異なる長さの値を受け入れることができなければならないので、1つの巨大な余分なテーブルになります! – dampkwab

+0

クエリが実行されるたびにメモリに膨大な余分なテーブルが作成され、インデックスの利点が得られません。 – txyoji

1

バットをストレートにすると、SELECT式とGROUP BYの両方でMID()クエリを使用しなくなります。クエリ条件にDepening、MySQLはこれを試して、少なくともので、必ずしも、解析しながら、単一の式の内部でそれをキャッシュしません。世界で

SELECT MID(game,{$len},1) AS move, 
    COUNT(*) AS games, 
    SUM(win) AS wins, 
    SUM(loss) AS losses 
    FROM games WHERE game LIKE '{$game}%' GROUP BY move; 

ない最大の変化が、それは小さな違いを作る必要があります。しかし、これ以外にも、データを保存する方法を変えることを短期間で最適化する唯一の方法は、これらの値を事前に計算し、ゲームの終了時にインクリメントすることです。

+1

ああ、ありがとうございます。私はちょうど私が作った柱を 'GROUP BY'できることに気付かなかった。また、 'LIKE'を'> x AND dampkwab

+0

クエリはGROUP BYを変更するとより速く実行し、LIKEの代わりに>と<を使用します。 LIKEはパターンマッチングと正規表現を使用して一致を計算しますが、>と<はブール演算子であり、直接アセンブリコードを使用して計算されます。 –

関連する問題