3

親切な SO ユーザーの助けを借りて、私が取り組んでいるタスクに対する論理的に正しい MySQL クエリを作成することができました。特定のタイプのグループ化されたアイテムを、そのグループの単一の代表にフィルタリングします。(ふぅ!)

残っている明らかな問題は、このクエリが非常に不格好で遅いことです。CakePHP のデータベース呼び出しのデバッグ出力によると、145000 ミリ秒の調整が必要です。

このような獣を飼いならすための賢明なアプローチはありますか、それとも、ここで噛むことができる以上に噛んでいることを認め、多かれ少なかれ同様の結果を達成する、それほど重くないアプローチを探す必要がありますか? すべての提案に感謝します。

    SELECT DISTINCT Uid.id, Uid.type
    FROM (SELECT uids.id id, uids_uids.parent_id parent_id, uids.created date,
                 uids.type type
          FROM uids 
          JOIN uids_uids ON uids_uids.uid_id = uids.id
          JOIN aros_uids ON uids.id = aros_uids.uid_id
          JOIN uids_uids ParentUids ON uids_uids.parent_id = ParentUids.uid_id
          WHERE uids.type IN ('Document','Photo','Release','PreRelease',
                              'ArtworkResource','Event') 
            AND (uids.start_date IS NULL OR uids.start_date <= NOW())
            AND (uids.end_date IS NULL OR uids.end_date <= NOW())
            AND aros_uids.aro_id IN (3,2,86,1448)
          ) Uid
    JOIN (SELECT uids_uids.parent_id parent_id, MAX(uids.created) maxdate
          FROM uids JOIN uids_uids
          ON uids_uids.uid_id = uids.id
          GROUP BY uids_uids.parent_id, uids.type) T2
    ON Uid.parent_id = T2.parent_id AND Uid.date = T2.maxdate
    ORDER BY Uid.date DESC
    LIMIT 100

到着予定時刻:

さて、最初のパスとして、これらのサブセレクトをビューに変えたので、クエリはもう少し管理しやすいように見えます

    SELECT DISTINCT Uid.id, Uid.type
    FROM UidView Uid
    JOIN UidView2 T2
    ON Uid.parent_id = T2.parent_id AND Uid.date = T2.maxdate
    WHERE Uid.aro_id IN (3,2,86,1448)
    ORDER BY Uid.date DESC
    LIMIT 100

これは間違いなく役に立ち、Cake の推定クエリ時間 (ミリ秒) が 6 桁から 2500 程度に短縮されました。間違いなく良いスタートです!

4

1 に答える 1

0

これが私が試すことです:

各派生クエリを取得し、EXPLAINそれぞれに対して個別に実行します。コメントが示唆するように、インデックスが欠落している行を確認し、必要に応じて追加します。EXPLAIN助けが必要な場合は、結果を投稿してください。そう

EXPLAIN SELECT uids.id id, uids_uids.parent_id parent_id, uids.created date, ....
EXPLAIN SELECT uids_uids.parent_id parent_id, MAX(uids.created) maxdate ....

インデックスを追加しても役に立たない、またはあまり役に立たない場合は、最初に各サブクエリを一時テーブルに入れて、それにインデックスを適用します。

CREATE TABLE temp_uid
SELECT uids.id id, uids_uids.parent_id parent_id, uids.created date,
             uids.type type
      FROM uids 
      JOIN uids_uids ON uids_uids.uid_id = uids.id
      JOIN aros_uids ON uids.id = aros_uids.uid_id
      JOIN uids_uids ParentUids ON uids_uids.parent_id = ParentUids.uid_id
      WHERE uids.type IN ('Document','Photo','Release','PreRelease',
                          'ArtworkResource','Event') 
        AND (uids.start_date IS NULL OR uids.start_date <= NOW())
        AND (uids.end_date IS NULL OR uids.end_date <= NOW())
        AND aros_uids.aro_id IN (3,2,86,1448);

CREATE TABLE temp_t2
SELECT uids_uids.parent_id parent_id, MAX(uids.created) maxdate
      FROM uids JOIN uids_uids
      ON uids_uids.uid_id = uids.id
      GROUP BY uids_uids.parent_id, uids.type;

そしてJOINそれらのテーブルで:

SELECT DISTINCT Uid.id, Uid.type
FROM temp_uid AS Uid
JOIN temp_t2 AS T2 ON Uid.parent_id = T2.parent_id AND Uid.date = T2.maxdate
ORDER BY Uid.date DESC
LIMIT 100;

前述したように、おそらくインデックスを追加する必要があり、おそらく一時テーブルの次の列に追加する必要があります。

ALTER TABLE temp_uid ADD INDEX parentDateIdx (parent_id, Uid.date);
ALTER TABLE temp_t2 ADD INDEX parentMaxDateIdx (parent_id, maxdate);

INSERT INTO temp_uid...SELECT一時テーブルを更新する必要がある場合INSERT INTO temp_t2...SELECTは、CREATE...SELECT. これには、ストアド プロシージャが最適です。

ところで、CREATE TABLE temp_t2...SELECT各一時テーブルに対して行った方法で を実行すると、最適なテーブル構造が作成されない可能性があるため、後で作成を変更するか、最初から自分で行う方がよい場合があります。

于 2012-10-17T15:07:34.727 に答える