2016-05-09 4 views
1

を使用すると、私は起動しようとしているクエリです:一時的な使用によるMySQLソート。ここでfilesortレコード

:ここ

enter image description here

creativesテーブル構造である:ここで

SELECT c.creative_id, c.creative_title, c.creative_image_name, c.gravity, c.ad_strength 
FROM creatives AS c 
INNER JOIN term_relationships AS tr ON c.creative_id = tr.creative_id 
WHERE tr.term_id 
IN (14, 1, 50, 76, 104) 
GROUP BY c.creative_id 
HAVING COUNT(tr.term_id) =5 
ORDER BY c.gravity ASC 
LIMIT 30; 

は、どのようなこのクエリの出力のEXPLAINです

CREATE TABLE `creatives` (
    `creative_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `scraper_id` bigint(20) unsigned DEFAULT NULL, 
    `creative_title` varchar(255) NOT NULL, 
    `creative_image_name` varchar(255) DEFAULT NULL, 
    `image_attrib` varchar(12) DEFAULT NULL, 
    `original_image_name` varchar(255) DEFAULT NULL, 
    `creative_subtext` varchar(255) DEFAULT NULL, 
    `dest_url` varchar(2083) NOT NULL, 
    `lp_url` varchar(2083) NOT NULL, 
    `lp_image_name` varchar(255) DEFAULT NULL, 
    `lp_image_flag` tinyint(1) unsigned NOT NULL DEFAULT '0', 
    `creative_first_seen` date NOT NULL, 
    `creative_last_seen` date NOT NULL, 
    `daily_ad_count` int(5) unsigned NOT NULL, 
    `ad_strength` int(11) unsigned NOT NULL, 
    `prev_ad_strength` int(11) unsigned DEFAULT NULL, 
    `gravity` int(11) unsigned DEFAULT NULL, 
    PRIMARY KEY (`creative_id`), 
    KEY `gravity` (`gravity`) 
) ENGINE=InnoDB AUTO_INCREMENT=173037591 DEFAULT CHARSET=utf8 

私は両者を起動するとUsing temporary; using filesortが心配です他の列にはGROUP BYORDER BYがあります。 ORDER BYを削除した場合、一時ファイルとファイル・セットがなくなり、クエリが本当に速く実行されます。

私は理解できませんが、なぜ一時的なテーブルが必要なのですか?c.gravityでフィルターを並べ替えてから、結果テーブルとグループをグループ化してHAVING節に従ってください。フィルタリングされたテーブルは、グループ化してフィルタを適用した後でも重力値が変更されないままであるため、c.gravityで正しくソートされます。私が試した何

ORDER BYなし

  1. 選択したすべてのもの、サブクエリの中に包み、creativesテーブルの上に再び参加しました - 一時的な、filesortレコードを使用して同じ結果を、ゆっくりと

  2. FORCE USE INDEX FOR ORDER BY (gravity)を追加しようとしましたし、それは何も変わらない。 EXPLAINと実行時間は変わりません。

UPDATE:質問は@Rickによって回答されており、それは本当に非常に速く、彼相関サブクエリではなくGROUP BYを使用しています。

enter image description here

そして、新しく作成されたインデックスを持つSHOW CREATE TABLE term_relationshipsの出力:

enter image description here

そして@Rickへの1つの以上の質問:なぜ私はここにクエリのEXPLAIN出力を追加していますc3という外部クエリが必要ですか? creativesに他の列の値を取得し、レコードを重力順に並べ替えるだけの方法があります。しかし、彼らはすでに、内側のクエリでソートされ、我々は簡単にそれを作るc1に欠けている列を追加することができます

SELECT c1.creative_id,c1.creative_title,c1.creative_image_name,c1.gravity, c1.ad_strength 
      FROM creatives AS c1 
      WHERE 
       (SELECT COUNT(*) 
        FROM term_relationships 
        WHERE c1.creative_id = creative_id 
         AND term_id IN (14, 1, 50, 76, 104) 
      ) = 5 
      ORDER BY c1.gravity ASC 
      LIMIT 30; 

が正しい私の理解ですか私はあなたのクエリで何かが足りないのですか?

+0

( 'c3'について)' c3'を指定しないと、 'creative_id'だけがtmpテーブル内を迂回します。 'c3'では、たくさんの列が巡回されます。 'LIMIT'(30)と' LIMITing'の前の行数に大きな違いがある場合、パフォーマンスの差が顕著になる可能性があります。 –

答えて

2

テンポラリテーブルとファイルセットは、それ自体が悪党ではありません。彼らはどれだけかさばっている。

これはより複雑に見えるかもしれないが、それは速くなることがあります。

SELECT c3.creative_id, 
     c3.creative_title, c3.creative_image_name, 
     c3.gravity, c3.ad_strength 
    FROM 
     (SELECT creative_id 
      FROM creatives AS c1 
      WHERE 
       (SELECT COUNT(*) 
        FROM term_relationships 
        WHERE c1.creative_id = creative_id 
         AND term_id IN (14, 1, 50, 76, 104) 
      ) = 5 
      ORDER BY c1.gravity ASC 
      LIMIT 30 
    ) AS c2 
    JOIN creatives c3 USING (creative_id) 
    ORDER BY c3.gravity 

それは内側のクエリのINDEX(gravity)を使用することが発生した場合、それはすべて5つのトランザクションを持っている30行を見つけた後停止します。 tmpテーブルを生成すると、元のクエリよりもはるかに良い30行になります。また、tmpテーブルが狭くなることに注意してください。creative_idしかそこにありません。最後に、creativesに戻り、残りの希望の列を取得します。最後に、もう1つのソートがありますが、30行しかありません。

さらに、「ファイル」は、実際には「ファイル」の並べ替えではなく、RAMの非常に高速な並べ替えであることがよくあります。私は私の質問がディスク上にはないと確信しています。

term_relationshipsには、この複合インデックス:INDEX(creative_id, term_id)が必要です。

+0

Rickさん、ありがとうございます。今日は試してみます。私はあなたに一目惚れでそれが本当に速く働くことを知らせます。あなたのコメントも見ていきます。どうもありがとう! – Alexey

+0

アップデート:テストし、コードを変更して使用しました - ありがとうございました。ところで、実際にグループを使用せずに+ count()でグループを書くのはとても興味深い方法です!私は 'terms_relationships'(creative_id、term_id)にあなたが言及したインデックスを追加しようとしましたが、' EXPLAIN'出力に従って使用されていません。 – Alexey

+0

これは "相関サブクエリ"であり、単一のカウントしか必要ないので、 'GROUP BY'は必要ありません。 'EXPLAIN SELECT ... 'を見てみましょう。私はそのインデックスを使用しないことに困惑しています。それは今すぐ "十分"速いですか? –

関連する問題