2017-11-23 5 views
2

games_releasesは、ゲーム情報を組み合わせたテーブルです。ゲームのタイトルのようなInfos、ゲームの出版社や開発者は、さまざまなゲームで同じであるため、後で一緒に結合される異なるテーブルに保存されます。JOINEDテーブルとORDER BYとOFFSETを使用してMySQLクエリを改善する方法

以下の例では、理解を容易にするためにテーブルを結合しています(実際には、同じ原則に従って結合されたテーブルがいくつかあります)。

games_releasesテーブル:games_releases

id   int(11)  <- unique 
title_id  int(11)  <- index 
developer_id int(11) 
... more game relevant data 

いくつかの典型的な行は次のようになります。

id title_id developer_id ... ... 
-------------------------------------------- 
1  17   265 
2  23   41 
3  31   3 
4  42   15 
5  17   123 

games_titlesテーブル:games_titles

id  int(11)  <- unique 
title varchar(128) 
created int(11) 

いくつかの典型的な行は次のようになります:

id title  created 
---------------------------------------- 
17 Pac-Man [some unix timestamp] 
23 Defender [some unix timestamp] 
31 Scramble [some unix timestamp] 
42 Q*bert [some unix timestamp] 
99 Phoenix [some unix timestamp] 

NOW:

SELECT 
    id AS release_id, t.`title` AS title 
FROM 
    games_releases 

LEFT JOIN games_titles t ON t.`id`=`games_releases`.`title_id` 
ORDER BY title 
LIMIT 24 

...その後、このクエリが実行されるだろう、のは(当時24)は、ユーザがアルファベット順にすべてのゲームを見たいと仮定しましょうこれは

を返されます
release_id title 
----------------------------- 
2    Defender 
1    Pac-Man 
5    Pac-Man 
4    Q*Bert 
3    Scramble 

基本的に結果の表には、IDではなく文字列が表示されます。

チャレンジ:このクエリは実行に時間がかかります(games_releasesは約80.000個のアイテムが表示されますが、データベースは1.000.000個に増えたとします)。ここで

は私に語ったかを説明ある(games_releasesは、インデックスのtitle_idを持つ):

id select_type table partitions type possible_keys key key_len ref rows Extra 
1 SIMPLE games_releases NULL index NULL title_id 4 NULL 76669 Using index; Using temporary; Using filesort 
1 SIMPLE t NULL eq_ref PRIMARY PRIMARY 4 phoenix.games_releases.title_id 1 

これを最適化するために、任意のチャンスを?

EDIT:質問に回答しました。 「JOIN」の代わりに間違った「LEFT JOIN」が問題でした。

But:オフセットが大きくなるにつれて実行時間を長くするにはどうすればよいですか?

複数のJOINを実行しているときにインデックスを効率的に設定する方法を理解するのは難しいですが、

games_titlesの「タイトル」インデックスを持つことは効果がないようです。

+0

することができますそのgames_releases adn game_titlesは一致しません??? – scaisEdge

+0

こちらをお読みください。 http://meta.stackoverflow.com/a/271056/クエリの最適化に関するセクションに特に注意してください。それから、あなたの質問を編集して、より多くの情報を提供してください。ちなみに、MySQLクエリプランナーは、ビューをサブクエリとして扱うため、ビューを最適化しても外部クエリが最適化されるとは限りません。 –

+0

@ O.Jones私はこれをすでにやったと思う。問題のクエリとEXPLAINがあります。私はDBの構造を広告します。 –

答えて

0

今後の参照用:クエリのパフォーマンスに関する質問は、クエリに含まれる各テーブルの出力SHOW CREATE TABLE tablenameを提示する必要があります。テーブル構造はパフォーマンスに大きな違いをもたらします。

games_releasesテーブルに一致するものがあるgames_titlesテーブルからアルファベット順に最初の24タイトルを表示するように見えます。私はあなたのLEFT JOINの論理を理解していません。games_releasesにタイトルの行が複数ある場合は、タイトルを繰り返しますか? の行がgames_titlesの行と一致しない行で何をしたいですか?

私は次のようにあなたが望む結果を得ることができると思う:

SELECT DISTINCT t.id, t.title 
    FROM games_titles t 
    JOIN games_releases r ON t.id = r.title_id 
    ORDER BY t.title 
    LIMIT 24 

これは、リリーステーブルには何も一致するあなたのtitlesテーブルとは別の行を提供します。これはおそらくそのパフォーマンスにおいて最適なものになるでしょう。最初の24タイトルについて、アルファベット順に、アプリケーションで重要なことと、それがなぜ重要視されているのだろうと思います。

SELECT lots, of, stuff .... ORDER BY something LIMIT numberは、悪名高いパフォーマンスの反パターンです。どうして? MySQLは多くのデータをソートしなければならず、少量のデータを破棄する必要があります。ビューの定義の限界により、ビュー内でより効率的なものを行うことが難しくなります。

games_titles.idがインデックスに登録されているかどうかを教えてください。インデックスを作成する必要があります。プライマリキーの場合はインデックスが作成されます。

+0

私が不明な場合は申し訳ありません。目的は:テーブルgames_releasesは、他のテーブルを参照する(正規化)多くの行を持っています。私が望むのは、アルファベット順にgames_releasesからSELECTを得ることです。ですから、私はgames_titlesからではなく、games_releasesから行を取り出したいと思っています。 games_releases行にはゲームに関するすべての情報が含まれ、games_titlesにはゲームの名前しかありません。だから、リリースの名前を取得するためにgames_titleテーブルを参照するだけで、同じ名前の100のリリースが存在する可能性があります。私は次の編集でうまく説明します。 –

+0

私はそれをよりよく説明するために最善を尽くしました。私はあなたがそれをもう一度見ていただければ大変感謝しています... –

+1

左の結合を内部結合に置き換えると(もちろんタイトル欄にインデックスを追加する)、テーブルの順番を変えてこれを高速に処理するようにMySQLに説得してください。 – peufeu

関連する問題