MYSQL トリプル結合パフォーマンスのヘルプ、Tmp テーブルへのコピー
-
29-10-2019 - |
質問
私はニュース サイトのクエリを作成しています。このクエリでは、メインのホームページに表示する FeaturedContent を検索します。この方法でマークされたコンテンツは「FeaturedContent」としてタグ付けされ、特集テーブル内で「ホームページ」ごとに並べられます。現在、目的の出力が得られていますが、クエリの実行には 3 秒以上かかるため、これを短縮する必要があります。次のようなクエリを最適化するにはどうすればよいでしょうか?
編集:提案どおり、ビューを 0.4 秒まで毎分実体化します。
SELECT f.position, s.item_id, s.item_type, s.title, s.caption, s.date
FROM live.search_all s
INNER JOIN live.tags t
ON s.item_id = t.item_id AND s.item_type = t.item_type AND t.tag = 'FeaturedContent'
LEFT OUTER JOIN live.featured f
ON s.item_id = f.item_id AND s.item_type = f.item_type AND f.feature_type = 'homepage'
ORDER BY position IS NULL, position ASC, date
これにより、ホームページのすべての機能が順番に返され、その後に日付順に並べられたその他の注目のコンテンツが返されます。
説明は次のようになります。
|-id---|-select_type-|-table-|-type---|-possible_keys---------|-key--------|-key_len-|-ref---------------------------------------|-rows--|-Extra-------------------------------------------------------------|
|-1----|-SIMPLE------|-t2----|-ref----|-PRIMARY,tag_index-----|-tag_index--|-303-----|-const-------------------------------------|-2-----|-Using where; Using index; Using temporary; Using filesort;--------|
|-1----|-SIMPLE------|-t-----|-ref----|-PRIMARY---------------|-PRIMARY----|-4-------|-newswires.t2.id---------------------------|-1974--|-Using index-------------------------------------------------------|
|-1----|-SIMPLE------|-s-----|-eq_ref-|-PRIMARY, search_index-|-PRIMARY----|-124-----|-newswires.t.item_id,newswires.t.item_type-|-1-----|-------------------------------------------------------------------|
|-1----|-SIMPLE------|-f-----|-index--|-NULL------------------|-PRIMARY----|-190-----|-NULL--------------------------------------|-13----|-Using index-------------------------------------------------------|
そしてプロフィールは以下の通りです。
|-Status---------------|-Time-----|
|-starting-------------|-0.000091-|
|-Opening tables-------|-0.000756-|
|-System lock----------|-0.000005-|
|-Table lock-----------|-0.000008-|
|-init-----------------|-0.000004-|
|-checking permissions-|-0.000001-|
|-checking permissions-|-0.000001-|
|-checking permissions-|-0.000043-|
|-optimizing-----------|-0.000019-|
|-statistics-----------|-0.000127-|
|-preparing------------|-0.000023-|
|-Creating tmp table---|-0.001802-|
|-executing------------|-0.000001-|
|-Copying to tmp table-|-0.311445-|
|-Sorting result-------|-0.014819-|
|-Sending data---------|-0.000227-|
|-end------------------|-0.000002-|
|-removing tmp table---|-0.002010-|
|-end------------------|-0.000005-|
|-query end------------|-0.000001-|
|-freeing items--------|-0.000296-|
|-logging slow query---|-0.000001-|
|-cleaning up----------|-0.000007-|
EXPLAIN 出力を読むのは初めてなので、もっと良い順序付けができるかどうか、それとも処理を高速化するためにできる比較的簡単な方法があるかどうかわかりません。
search_all テーブルは定期的に更新されるマテリアライズド ビュー テーブルであり、タグと注目のテーブルはビューです。これらのビューはオプションではないため、回避することはできません。
タグ ビューは、タグとリレーショナル テーブルを組み合わせて、item_type と item_id に従ってタグのリストを取得しますが、他のビューはすべて 1 つのテーブルの単純なビューです。
編集:マテリアライズド ビューの場合、最大のボトルネックは「一時テーブルへのコピー」ステップのようです。出力を順序付けしないと、0.0025 秒かかります (はるかに優れています!) が、最終出力には順序付けが必要です。そのステップのパフォーマンスを向上させる方法、またはそれを回避する方法はありますか?
フォーマットが読みにくかったら申し訳ありません。私は初心者なので、定期的にどのように行われるかわかりません。
ご協力いただきありがとうございます!他に何か必要な場合は、お知らせください。
編集:テーブルサイズの参考:
タグ関係:197,411
タグ:16,897
ストーリー:51,801
画像:28,383
動画:2,408
特徴:13
解決
クエリを最適化するだけではあまり役に立たないと思います。最初に考えられるのは、それ自体が UNION で構成されているサブクエリに参加すること自体が、パフォーマンスの二重のボトルネックになるということです。
データベース構造を変更できる場合は、3 つのテーブルをマージすることをお勧めします。 stories
, images
そして videos
見た目が非常に似ている場合は、1 つにまとめます (それらを 1 つに追加します)。 type ENUM('story', 'image', 'video')
) レコードを区別するため。これにより、サブクエリとユニオンの両方が削除されます。
また、あなたの見解は次のようです stories
そして videos
, 、インデックス付きフィールドを使用してコンテンツをフィルタリングしていません。インデックス付きの列をクエリしていますか?
これは、完全なテーブル構造とデータの再分割を理解していなければ、かなり難しい問題です。
既存のデータベース (特にすでに運用されている場合) に変更を加えない別のオプションは、この情報を別のテーブルに「キャッシュ」し、cron ジョブによって定期的に更新することです。
キャッシュは、クエリ全体、またはクエリのサブパート (独立したビュー、または 1 つのキャッシュ テーブルにマージされた 3 つのユニオンなど) のいずれかで、さまざまなレベルで実行できます。
このオプションが有効かどうかは、多少古いデータの表示が許容されるかどうかによって決まります。データの一部のみが許容される場合があります。これは、クエリに含まれるテーブル/ビューのサブセットのみをキャッシュすることを意味する場合があります。