1

MySQLの説明を読み、理解し、最適化する方法を理解するのにまだ問題があります。orderby列にインデックスを作成することは知っていますが、それだけです。したがって、このクエリの調整にご協力いただければ幸いです。

EXPLAIN
SELECT specie.id, specie.commonname, specie.block_description, maximage.title,
       maximage.karma, imagefile.file_name, imagefile.width, imagefile.height,
       imagefile.transferred
FROM specie
INNER JOIN specie_map ON specie_map.specie_id = specie.id
INNER JOIN (
    SELECT *
    FROM image
    ORDER BY karma DESC
) AS maximage ON specie_map.image_id = maximage.id
INNER JOIN imagefile ON     imagefile.image_id = maximage.id
                        AND imagefile.type = 'small'
GROUP BY specie.commonname
ORDER BY commonname ASC
LIMIT 0 , 24 

このクエリが行うことは、種のカルマが最も多い写真を見つけることです。このライブの結果を見ることができます:

http://www.jungledragon.com/species

画像ごとに複数の画像ファイル(フォーマット)があるため、種のテーブル、画像のテーブル、その間のマッピングテーブル、および画像ファイルテーブルがあります。

出力の説明:

ここに画像の説明を入力してください

種のテーブルについては、プライマリIDとフィールドcommonnameにインデックスがあります。画像テーブルについては、idフィールドとkarmaフィールドにインデックスがあり、他にもこの質問に関係のないものがいくつかあります。

このクエリは現在0.8から1.1秒かかりますが、私の意見では遅すぎます。正しいインデックスがこれを何度もスピードアップするのではないかと疑っていますが、どれがどれかわかりません。

4

3 に答える 3

1

テーブル構造とインデックスを提供できればもっと良いでしょう。私はこの代替案を思いついたので、これを試して何が起こるか教えていただければ幸いです(私は興味があります!):

SELECT t.*, imf.* FROM (
  SELECT s.*, (SELECT id FROM image WHERE karma = MAX(i.karma) LIMIT 1) AS max_image_id 
  FROM image i 
  INNER JOIN specie_map smap ON smap.image_id = i.id
  INNER JOIN specie s ON s.id = smap.specie_id
  GROUP BY s.commonname 
  ORDER BY s.commonname ASC
  LIMIT 24
) t INNER JOIN imagefile imf
ON t.max_image_id = imf.image_id AND imf.type = 'small' 
于 2012-03-25T14:19:59.390 に答える
1

本当の問題は、MySQLの説明を最適化する必要がないことです。通常、効率的にしたいクエリ(または複数のクエリ)がEXPLAINあり、クエリの実行が期待どおりに行われるかどうかを確認する方法です。

つまり、実行プランがどのように表示されるか、およびその理由を理解し、EXPLAINコマンドの結果と比較する必要があります。計画がどのように見えるかを理解するには、MySQLのインデックスがどのように機能するかを理解する必要があります。

それまでの間、クエリはトリッキーなものです。効率的なインデックスを使用するには、いくつかの制限があります。a)あるテーブルのフィールドによる同時順序付け、およびb)別のグループからの各グループの最後の要素の検索(後者はそれ自体としてトリッキーなタスク)。データベースはかなり小さいので、現在のクエリがかなり速いのは幸運です(ただし、遅いと思います)。

少しハッキーな方法でクエリを書き直します(種ごとに少なくとも1枚の写真があると思います)。

SELECT
   specie.id, specie.commonname, specie.block_description,
   maximage.title, maximage.karma,
   imagefile.file_name, imagefile.width, imagefile.height, imagefile.transferred
FROM (
    SELECT s.id,
           (SELECT i.id
            FROM specie_map sm
            JOIN image i ON sm.image_id = i.id
            WHERE sm.specie_id = s.id
            ORDER BY i.karma DESC
            LIMIT 1) as image_id
    FROM specie s
    ORDER BY s.commonname
    LIMIT 0, 24
) as ids
JOIN specie
  ON ids.id = specie.id
JOIN image as maximage
  ON maximage.id = ids.image_id
JOIN imagefile
  ON imagefile.image_id = ids.image_id AND imagefile.type = 'small';

次のインデックスが必要になります。

  • (commonname)の上specie
  • (specie_id, image_id)上のコンポジットspecie_map
  • (id, karma)上のコンポジットimage
  • (image_id, type)上のコンポジットimagefile

これで、ページングは​​サブクエリ内で発生するはずです。

アイデアは、IDのみで動作し、上部の残りのデータを結合するサブクエリ内で複雑な計算を行うことです。データは、サブクエリの結果の順序で並べられます。

于 2012-03-25T15:02:32.507 に答える
1

サブクエリを削除することで、すばらしい方法が得られると思います。「explain」結果の最初と最後の行を見てください。これは、「image」テーブル全体を一時テーブルにコピーしています。サブクエリをで置き換えて最後の句INNER JOIN imageに移動することで、同じ結果を得ることができます。ORDER BY karma DESCORDER BY

SELECT specie.id, specie.commonname, specie.block_description, maximage.title,
       maximage.karma, imagefile.file_name, imagefile.width, imagefile.height,
       imagefile.transferred
FROM specie
INNER JOIN specie_map ON specie_map.specie_id = specie.id
INNER JOIN image AS maximage ON specie_map.image_id = maximage.id
INNER JOIN imagefile ON     imagefile.image_id = maximage.id
                        AND imagefile.type = 'small'
GROUP BY specie.commonname
ORDER BY commonname ASC, karma DESC
LIMIT 0 , 24 
于 2012-03-25T21:41:02.683 に答える