次のクエリを最適化する必要があります。
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM blogposts
JOIN articles ON articles.blogpost_id = blogposts.id
WHERE blogposts.deleted = 0
AND blogposts.title LIKE '%{de}%'
AND blogposts.visible = 1
AND blogposts.date_published <= NOW()
ORDER BY blogposts.date_created DESC
LIMIT 0 , 50
EXPLAIN SELECTを実行すると、次の結果が得られます。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles ALL blogpost_id NULL NULL NULL 6915 Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where
なぜ最初に記事、次にブログ記事が表示されるのですか?ブログ投稿のエントリが多いからですか?そして、記事投稿がインデックスを使用できるように、クエリをどのように改善できますか?
pdate: blogposts.date_createdにインデックスが設定されます。 blogposts.title LIKE条件とdate_published <= NOW()を削除しても何も起こりません。
"articles.id AS articleid"を削除すると、記事のblogpost_idインデックスを使用できます...私には奇妙に聞こえますが、誰かが理由を知っていますか? (私は実際にそれを必要とするので..)
新しい説明は次のようになります。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles index blogpost_id blogpost_id 4 NULL 6915 Using index; Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where
クエリを詳しく調べたところ、あなたはそれを再設計できるかもしれません。これが私の意味です:
クエリのLIMIT 0,50部分は、最後のクエリでビジー状態になっているようです。
次の操作を行うことにより、クエリのレイアウトを改善できます。
手順1)キーのみを収集するインラインクエリを作成します。この場合、ブログ投稿のID。
ステップ2)キーをもたらすインラインクエリにWHERE、ORDER BY、GROUP BY句を適用します。
手順3)インラインクエリを作成する最後の手順として、LIMIT句を挿入します。
ステップ4)ブログポストの追加の列がブロストポストのテンプレートとして必要な場合は、インラインクエリをブログポストテーブルと結合します。
手順5)この新しいブログ投稿をアーティクルテーブルと結合します。
手順1〜3は、正確に50行のテンプレートを作成し、ブログ投稿IDを含めることを目的としています。次に、すべてのJOINを最後に実行します。
これらの手順を元のクエリに適用すると、次のようになります。
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT B.*
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
AND title LIKE '%{de}%'
ORDER BY date_created DESC
LIMIT 0,50
) A
INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
質問を編集して、LIKEを削除すると述べたので、クエリは次のようになります。
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT B.*
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
ORDER BY date_created DESC
LIMIT 0,50
) A
INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
[省略されたもの]というフレーズで、キー以外にブログ投稿から何も必要ない場合、クエリは次のようになります。
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
ORDER BY date_created DESC
LIMIT 0,50
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id;
警告
次のように、削除、表示、およびdate_createdの列を含むインデックスを作成してください。
ALTER TABLE blogposts ADD INDEX deleted_visible_date_created (deleted,visible,date_created);
試してみる !!!
Where条件blogposts.title LIKE '%{de}%'
はblogpostsテーブルで全テーブルスキャンを実行します。 MySQLの数値が6915の記事をスキャンする方が効率的である可能性があります。
それを改善する方法として、date_created
またはdate_published
を使用してblogpostsにインデックスを追加し、where条件に範囲を追加することができます(<= NOW以外のもの) ())
AND blogposts.title LIKE '%{de}%'-最適化には役に立たない(先頭のワイルドカード)
WHERE blogposts.deleted = 0 AND blogposts.visible = 1-残念:表示する必要がない場合は、テーブルから除外してください。
AND blogposts.date_published <= NOW()ORDER BY blogposts.date_created DESC LIMIT 0、50-その結果、INDEX(date_published)が必要になります(ただし、LIKEとフラグにより、このインデックスは使用できなくなる場合があります)。
SHOW CREATE TABLE ...;を指定してください。表のステータスを表示...;
どうもありがとうございました :)
私はそれを試してみましたが、インデックスに関する実際の最後のコメントが実際に必要なものであることがわかりました。時々、それは必要とされるほんの少しの改善です...;)比較:
古いクエリ:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM blogposts
JOIN articles ON articles.blogpost_id = blogposts.id
WHERE blogposts.deleted = 0
AND blogposts.title LIKE '%{de}%'
AND blogposts.visible = 1
AND blogposts.date_published <= NOW()
ORDER BY blogposts.date_created DESC
LIMIT 0 , 50
新しいクエリ:
SELECT /* [things omitted] */ articles.blogpost_id, articles.id AS articleid
FROM
(
SELECT B.*
FROM
(
SELECT id FROM blogposts
WHERE date_published <= NOW()
AND deleted = 0 AND visible = 1
AND title LIKE '%{de}%'
ORDER BY date_created DESC
LIMIT 0,50
) A
INNER JOIN blogposts B USING (id)
) blogposts
INNER JOIN articles
ON blogposts.id = articles.blogpost_id
今言及されたインデックスなし:
古い説明の結果:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE articles ALL blogpost_id NULL NULL NULL 6915 Using temporary; Using filesort
1 SIMPLE blogposts eq_ref PRIMARY PRIMARY 4 articles.blogpost_id 1 Using where
新しい説明結果:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 50
1 PRIMARY articles ref blogposts_id blogposts_id 4 blogposts.id 1
2 DERIVED <derived3> ALL NULL NULL NULL NULL 50
2 DERIVED B eq_ref PRIMARY PRIMARY 4 A.id 1
3 DERIVED blogposts ALL deleted,visible,date_published deleted 1 28198 Using filesort
古いクエリのインデックスで結果を説明:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE blogposts ref PRIMARY,deleted,visible,date_published,deleted_vis... deleted_visible_date_created 2 const,const 27771 Using where
1 SIMPLE articles ref blogposts_id blogposts_id 4 db.blogposts.id 1
新しいクエリのインデックスで結果を説明:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 50
1 PRIMARY articles ref blogposts_id blogposts_id 4 blogposts.id 1
2 DERIVED <derived3> ALL NULL NULL NULL NULL 50
2 DERIVED B eq_ref PRIMARY PRIMARY 4 A.id 1
3 DERIVED blogposts ref deleted,visible,date_published,deleted_visible_dat... deleted_visible_date_created 2 27771 Using where
インデックスなし/ありの古いクエリの速度: 0.1835/0.0037
インデックスなし/ありの新しいクエリの速度: 0.1883/0.0035
したがって、古いクエリと新しいクエリのわずかな違いのため、古いクエリを使用することをお勧めしますが、インデックスを使用します。しかし、いつか古いクエリが遅すぎるかのように、これを覚えておきます:)
私にとって興味深いのは、どのようにしてこのようにインデックスを設定するアイデアを得たのかを知ることです。私はこの質問を公開したときに、deleted_visibleも試しましたが、date_createdの代わりにdate_publishedを使用しました(where句にあるため)...
ありがとう:)
RolandoMySQLDBA 2011-05-19 13:03による更新
私にそれを与えたのは、WHERE句とORDER BY句でした。
WHERE句では、削除済み(0)および表示可能(1)は静的な値です。 ORDER BY句では、date_createdはdeleted = 0およびvisible = 1のすべての行の間で移動するターゲットのようでした。したがって、静的変数を最初にインデックスの前に配置し、次に移動ターゲットをインデックスの最後に配置しました。通常、これはSQLステートメントをリファクタリングする基本的な原則の一部です。 WHERE、GROUP BY、およびORDER句をサポートするインデックスが必要です。