正規化された注文データの大規模なデータベースがあり、レポートのクエリが非常に遅くなっています。レポートで使用するクエリの多くは、5つまたは6つのテーブルを結合し、数万または数十万の行を調べる必要があります。
クエリはたくさんあり、そのほとんどはサーバーの負荷を減らして速度を上げるために可能な限り最適化されています。非正規化された形式でデータのコピーを保持し始める時が来たと思います。
アプローチに関するアイデアはありますか?いくつかの最悪のクエリから始めて、そこから進む必要がありますか?
正規化された注文データの大規模なデータベースがあり、レポートのクエリが非常に遅くなっています。レポートで使用するクエリの多くは、5つまたは6つのテーブルを結合し、数万または数十万の行を調べる必要があります。
クエリはたくさんあり、そのほとんどはサーバーの負荷を減らして速度を上げるために可能な限り最適化されています。非正規化された形式でデータのコピーを保持し始める時が来たと思います。
アプローチに関するアイデアはありますか?いくつかの最悪のクエリから始めて、そこから進む必要がありますか?
私はそのmysqlのmssqlについてもっと知っていますが、あなたが話している結合の数や行の数が、適切なインデックスであまりにも多くの問題を引き起こすとは思わない。クエリプランを分析して、不足していないかどうかを確認しましたか?
http://dev.mysql.com/doc/refman/5.0/en/explain.html
そうは言っても、インデックスに満足し、他のすべての手段を使い果たしたら、非正規化が正しい答えかもしれません。問題のあるクエリが1つか2つしかない場合は、手動によるアプローチがおそらく適切ですが、データキューブを開発するためのプラットフォームを作成するには、ある種のデータウェアハウスツールの方が適している場合があります。
これが私が見つけたこのテーマに触れているサイトです:
http://www.meansandends.com/mysql-data-warehouse/?link_body%2Fbody=%7Bincl%3AAggregation%7D
これは、一度にいくつかのクエリを実行している場合に、クエリの非正規化を単純に保つために使用できる簡単な手法です(OLTPテーブルを置き換えるのではなく、レポート用に新しいテーブルを作成するだけです)。アプリケーションに次のクエリがあるとします。
select a.name, b.address from tbla a
join tblb b on b.fk_a_id = a.id where a.id=1
非正規化されたテーブルを作成し、ほぼ同じクエリを入力できます。
create table tbl_ab (a_id, a_name, b_address);
-- (types elided)
下線が使用するテーブルエイリアスと一致することに注意してください
insert tbl_ab select a.id, a.name, b.address from tbla a
join tblb b on b.fk_a_id = a.id
-- no where clause because you want everything
次に、新しい非正規化テーブルを使用するようにアプリを修正するには、アンダースコアのドットを切り替えます。
select a_name as name, b_address as address
from tbl_ab where a_id = 1;
巨大なクエリの場合、これにより多くの時間を節約でき、データの出所が明確になり、既存のクエリを再利用できます。
覚えておいてください、私はこれを最後の手段としてのみ提唱しています。私はあなたを助けるであろういくつかのインデックスがあるに違いない。また、非正規化するときは、ディスク上の余分なスペースを考慮することを忘れないでください。また、クエリを実行して新しいテーブルにデータを入力するタイミングを把握してください。これはおそらく夜、または活動が少ないときはいつでもあるはずです。もちろん、そのテーブルのデータが正確に最新になることはありません。
[さらに別の編集]作成する新しいテーブルにもインデックスを付ける必要があることを忘れないでください。良い部分は、一括挿入を除いてテーブルには選択のみが表示されるため、更新ロックの競合について心配することなく、心のコンテンツにインデックスを付けることができることです。
他のコメントのいくつかと一致して、私は間違いなくあなたの索引付けを見るでしょう。
今年初めにMySQLデータベースで発見したことの1つは、複合インデックスの能力でした。たとえば、日付範囲の注文番号についてレポートする場合は、注文番号と注文日の列の複合インデックスが役立ちます。MySQLはクエリに1つのインデックスしか使用できないと思います。そのため、注文番号と注文日に別々のインデックスがある場合は、使用するインデックスを1つだけ決定する必要があります。EXPLAINコマンドを使用すると、これを判別するのに役立ちます。
優れたインデックス(多数の複合インデックスを含む)のパフォーマンスを示すために、データベース内の3つのテーブルを結合するクエリを実行して、ほとんどの場合、ほぼ瞬時に結果を得ることができます。より複雑なレポートの場合、ほとんどのクエリは10秒未満で実行されます。これらの3つのテーブルには、それぞれ3,300万、1億1,000万、1億4,000万の行があります。データベースで最も一般的なクエリを高速化するために、これらもすでにわずかに正規化されていることに注意してください。
テーブルとレポートクエリの種類に関する詳細情報により、さらに提案が可能になる場合があります。
これは少し接線方向ですが、追加できるインデックスが他にもあるかどうかを確認してみましたか?
DBのバックグラウンドはあまりありませんが、最近データベースを頻繁に使用しており、インデックスを追加するだけで多くのクエリを改善できることがわかりました。
DB2を使用しており、db2explnおよびdb2advisというコマンドがあります。1つ目はテーブルスキャンとインデックススキャンのどちらが使用されているかを示し、2つ目はパフォーマンスを向上させるために追加できるインデックスを推奨します。MySQLにも同様のツールがあると確信しています...
とにかく、これがあなたがまだ考えていないことなら、それは私に大いに役立っています...しかし、あなたがすでにこのルートを進んでいるなら、それはあなたが探しているものではないと思います。
もう1つの可能性は、「マテリアライズド・ビュー」(またはDB2ではそれと呼ばれる)です。これにより、基本的に複数のテーブルのパーツで構成されるテーブルを指定できます。したがって、実際の列を正規化するのではなく、データにアクセスするためにこのビューを提供できます...しかし、これが挿入/更新/削除に深刻なパフォーマンスの影響を与えるかどうかはわかりません(ただし、「マテリアライズ」されている場合は、値は物理的に個別に保存されるため、選択に役立ちます)。
MySQL については、 Real World Web: Performance & Scalability, MySQL Editionという講演が好きです。これには、MySQL をさらに高速化するためのさまざまなアドバイスが含まれています。
以前の回答に加えて、状況によっては、主要なレポートデータを個別の要約テーブルに保存するという別のアプローチを採用しました。非正規化と最適化を行った後でも遅くなる特定のレポートクエリがあり、テーブルを作成し、月全体の現在の合計または要約情報を保存すると、月末のレポートもはるかに高速になることがわかりました。
このアプローチは、すでに機能していたものを壊さなかったため、実装が簡単であることがわかりました。これは、特定の時点での追加のデータベース挿入にすぎません。
また、一時テーブルを選択してから、その一時テーブルに対してクエリを実行することを検討することもできます。これにより、発行するすべてのクエリに対してテーブルを再結合する必要がなくなります(もちろん、多数のクエリに一時テーブルを使用できると仮定します)。これにより、基本的に非正規化されたデータが得られますが、select呼び出しのみを実行している場合は、データの一貫性について心配する必要はありません。
私は複合インデックスをいじっていて、いくつかの本当の利点を見てきました...おそらく、それがここで私を救うことができるかどうかを確認するためにいくつかのテストをセットアップします..少なくとももう少し長く。