これは非常に興味深いクエリです。その最適化中に、MySQLがどのように機能するかについての多くの新しい情報を発見して理解することができます。すべてを一度に詳細に書く時間があるかどうかはわかりませんが、徐々に更新することができます。
なぜ遅いのか
基本的に2つのシナリオがあります:クイック と遅い 。
クイック 事前定義された順序でテーブル上を歩き、おそらく同時に、他のテーブルから各行のIDごとにデータをすばやくフェッチするシナリオ。この場合、LIMIT句で指定された十分な行ができたらすぐに歩行を停止します。注文はどこから来ますか?テーブルにあるbツリーインデックスまたはサブクエリの結果セットの順序から。
遅い 事前定義された順序がなく、MySQLがすべてのデータを一時テーブルに暗黙的に配置し、テーブルをあるフィールドで並べ替えて、 nを返す必要があるシナリオ LIMIT句の行。その一時テーブルに入力したフィールドのいずれかがTEXTタイプ(VARCHARではない)の場合、MySQLはそのテーブルをRAMに保持しようとせず、ディスク上でフラッシュして並べ替えます(したがって追加のIO処理)。
最初に修正すること
順序に従うことができるインデックスを作成できない状況は多くあります(たとえば、異なるテーブルの列をORDER BYする場合)。そのような状況での経験則は、MySQLが配置するデータを最小限に抑えることです。一時テーブルで。どうすればいいですか?サブクエリで行の識別子のみを選択し、IDを取得したら、IDをテーブル自体および他のテーブルに結合してコンテンツをフェッチします。つまり、注文のある小さなテーブルを作成してから、クイックシナリオを使用します。 (これは一般的なSQLとは少し矛盾しますが、SQLの各フレーバーには、そのようにクエリを最適化する独自の手段があります。)
偶然にも、SELECT -- everything is ok here
それは大丈夫ではない最初の場所なので、面白そうに見えます。
SELECT p.*
, u.name user_name, u.status user_status
, c.name city_name, t.name town_name, d.name dist_name
, pm.meta_name, pm.meta_email, pm.meta_phone
, (SELECT concat("{",
'"id":"', pc.id, '",',
'"content":"', replace(pc.content, '"', '\\"'), '",',
'"date":"', pc.date, '",',
'"user_id":"', pcu.id, '",',
'"user_name":"', pcu.name, '"}"') last_comment_json
FROM post_comments pc
LEFT JOIN users pcu ON (pcu.id = pc.user_id)
WHERE pc.post_id = p.id
ORDER BY pc.id DESC LIMIT 1) AS last_comment
FROM (
SELECT id
FROM posts p
WHERE p.status = 'published'
ORDER BY
(CASE WHEN p.created_at >= unix_timestamp(now() - INTERVAL p.reputation DAY)
THEN +p.reputation ELSE NULL END) DESC,
p.id DESC
LIMIT 0,10
) ids
JOIN posts p ON ids.id = p.id -- mind the join for the p data
LEFT JOIN users u ON (u.id = p.user_id)
LEFT JOIN citys c ON (c.id = p.city_id)
LEFT JOIN towns t ON (t.id = p.town_id)
LEFT JOIN dists d ON (d.id = p.dist_id)
LEFT JOIN post_metas pm ON (pm.post_id = p.id)
;
これが最初のステップですが、今でも、不要な行に対してこれらの役に立たないLEFTJOINSとjsonのシリアル化を行う必要がないことがわかります。 (GROUP BY p.id
をスキップしました 、どのLEFT JOINが複数の行になるかわからないため、集計は行いません。
まだ書いていません:
- インデックス
- CASE句を再定式化します(UNION ALLを使用)
- おそらくインデックスを強制する