14

私はInnoDBを使用しています。

クエリ、説明、インデックス

選択する
  ストーリー。*、
  count(comments.id) AS コメント、
  GROUP_CONCAT(
    DISTINCT classifications2.name SEPARATOR ';'
  ) AS classifications_name,
  GROUP_CONCAT(
    DISTINCT images.id
    ORDER BY images.position,
    images.id SEPARATOR ';'
  ) as images_id,
  GROUP_CONCAT(
    DISTINCT images.caption
    ORDER BY images.position,
    images.id SEPARATOR ';'
  ) as images_caption,
  GROUP_CONCAT(
    DISTINCT images.thumbnail
    ORDER BY images.position,
    images.id SEPARATOR ';'
  ) as images_thumbnail,
  GROUP_CONCAT(
    DISTINCT images.medium
    ORDER BY images.position,
    images.id SEPARATOR ';'
  ) as images_medium,
  GROUP_CONCAT(
    DISTINCT images.large
    ORDER BY images.position,
    images.id SEPARATOR ';'
  ) as images_large,
  GROUP_CONCAT(
    DISTINCT users.id
    ORDER BY users.id SEPARATOR ';'
  ) as author_id,
  GROUP_CONCAT(
    DISTINCT users.display_name
    ORDER BY users.id SEPARATOR ';'
  ) as author_display_name,
  GROUP_CONCAT(
    DISTINCT users.url
    ORDER BY users.id SEPARATOR ';'
  ) AS author_url
から
  物語
  LEFT JOIN 分類
    ON stories.id = classifications.story_id
  LEFT JOIN 分類 AS 分類2
    ON stories.id = classifications2.story_id
  左結合のコメント
    オン stories.id = コメント.story_id
  LEFT JOIN image_story
    オン stories.id = image_story.story_id
      左結合画像
        ON images.id = image_story.`image_id`
  左結合
    オン stories.id = author_story.story_id
      LEFT JOIN ユーザー
        ON users.id = author_story.author_id
 WHERE classifications.`name` LIKE 'Home:Top%'
   AND ストーリー.ステータス = 1
GROUP BY stories.id
ORDER BY 分類.`名前`, 分類.`位置`

+----+-------------+------------------+--------+-- --------------+----------+---------+------------------ ------+--------------------+---------------------------------------------- ---------------+
| | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 エクストラ |
+----+-------------+------------------+--------+-- --------------+----------+---------+------------------ ------+--------------------+---------------------------------------------- ---------------+
| | 1 | シンプル | ストーリー | 参照 | ステータス | ステータス | 1 | 定数 | 434792 | where を使用します。一時的な使用; ファイルソートの使用 |
| | 1 | シンプル | 分類 | 参照 | ストーリーID | ストーリーID | 4 | ストーリー.id | 1 | where | の使用
| | 1 | シンプル | 分類2 | 参照 | ストーリーID | ストーリーID | 4 | ストーリー.id | 1 | where | の使用
| | 1 | シンプル | コメント | 参照 | ストーリーID | ストーリーID | 8 | ストーリー.id | 6 | where を使用します。インデックスの使用 |
| | 1 | シンプル | イメージストーリー | 参照 | ストーリーID | ストーリーID | 4 | ストーリー.id | 1 | ヌル |
| | 1 | シンプル | 画像 | eq_ref | プライマリ | プライマリ | 4 | image_story.image_id | 1 | ヌル |
| | 1 | シンプル | 著者ストーリー | 参照 | ストーリーID | ストーリーID | 4 | ストーリー.id | 1 | where | の使用
| | 1 | シンプル | ユーザー | eq_ref | プライマリ | プライマリ | 4 | author_story.author_id | 1 | where | の使用
+----+-------------+------------------+--------+-- --------------+----------+---------+------------------ ------+--------------------+---------------------------------------------- ---------------+

+-------------+------------+-------------+---- ----------+-------------+-----------+------------- +------------+--------+------+------------+
| | 表 | 表 一意でない | キー名 | Seq_in_index | 列名 | 照合 | カーディナリティ | サブパート | 梱包済み | ヌル | インデックスの種類 |
+-------------+------------+-------------+---- ----------+-------------+-----------+------------- +------------+--------+------+------------+
| | ストーリー | 0 | プライマリ | 1 | ID | あ | 869584 | ヌル | ヌル | | | Bツリー|
| | ストーリー | 1 | created_at | 1 | created_at | あ | 434792 | ヌル | ヌル | | | Bツリー|
| | ストーリー | 1 | ソース | 1 | ソース | あ | 2 | ヌル | ヌル | はい | Bツリー|
| | ストーリー | 1 | ソース ID | 1 | ソース ID | あ | 869584 | ヌル | ヌル | はい | Bツリー|
| | ストーリー | 1 | タイプ | 1 | タイプ | あ | 2 | ヌル | ヌル | | | Bツリー|
| | ストーリー | 1 | ステータス | 1 | ステータス | あ | 2 | ヌル | ヌル | | | Bツリー|
| | ストーリー | 1 | タイプ_ステータス | 1 | タイプ | あ | 2 | ヌル | ヌル | | | Bツリー|
| | ストーリー | 1 | タイプ_ステータス | 2 | ステータス | あ | 2 | ヌル | ヌル | | | Bツリー|
| | 分類 | 0 | プライマリ | 1 | ID | あ | 207 | ヌル | ヌル | | | Bツリー|
| | 分類 | 1 | ストーリーID | 1 | ストーリーID | あ | 207 | ヌル | ヌル | | | Bツリー|
| | 分類 | 1 | 名前 | 1 | 名前 | あ | 103 | ヌル | ヌル | | | Bツリー|
| | 分類 | 1 | 名前 | 2 | 位置 | あ | 207 | ヌル | ヌル | はい | Bツリー|
| | コメント | 0 | プライマリ | 1 | ID | あ | 239336 | ヌル | ヌル | | | Bツリー|
| | コメント | 1 | ステータス | 1 | ステータス | あ | 2 | ヌル | ヌル | | | Bツリー|
| | コメント | 1 | 日付 | 1 | 日付 | あ | 239336 | ヌル | ヌル | | | Bツリー|
| | コメント | 1 | ストーリーID | 1 | ストーリーID | あ | 39889 | ヌル | ヌル | | | Bツリー|
+-------------+------------+-------------+---- ----------+-------------+-----------+------------- +------------+--------+------+------------+

クエリ時間

平均0.035 secondsして実行に時間がかかります。

のみを削除するGROUP BYと、時間は0.007平均で に低下します。

フィルターのみを削除するstories.status=1と、時間は0.025平均に低下します。これは簡単に最適化できるようです。

そして、LIKEフィルターとORDER BY句のみを削除すると、時間は0.006平均にまで低下します。

更新 1: 2013 年 4 月 13 日

私の理解は、答えを経て多様化を改善しました。

author_storyとにインデックスを追加しました。これにより、images_storyクエリが0.025数秒で改善されたように見えましたが、何らかの奇妙な理由で、EXPLAIN計画ははるかに良く見えます。この時点で、ORDER BYクエリを削除すると0.015数秒に短縮され、両方ORDER BYを削除するとGROUP BY、クエリのパフォーマンスが に向上します0.006。私はこれらが今注目すべき2つのことですか?ORDER BY必要に応じて、アプリ ロジックに移動する場合があります。

ここに改訂版EXPLAININDEXES

+----+-------------+------------------+--------+-- -------------------------------+----------------------+------- --+-------------------------+---------------------+------------- -------------------------------------------+
| | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 エクストラ |
+----+-------------+------------------+--------+-- -------------------------------+----------------------+------- --+-------------------------+---------------------+------------- -------------------------------------------+
| | 1 | シンプル | 分類 | 範囲 | ストーリー ID,名前 | 名前 | 102 | ヌル | 14 | インデックス条件の使用; 一時的な使用; ファイルソートの使用 |
| | 1 | シンプル | ストーリー | eq_ref | プライマリ、ステータス | プライマリ | 4 | 分類.物語_id | 1 | where | の使用
| | 1 | シンプル | 分類2 | 参照 | ストーリーID | ストーリーID | 4 | ストーリー.id | 1 | where | の使用
| | 1 | シンプル | 著者ストーリー | 参照 | author_id,story_id,author_story | ストーリーID | 4 | ストーリー.id | 1 | インデックス条件の使用 |
| | 1 | シンプル | ユーザー | eq_ref | プライマリ | プライマリ | 4 | author_story.author_id | 1 | where | の使用
| | 1 | シンプル | コメント | 参照 | ストーリーID | ストーリーID | 8 | ストーリー.id | 8 | where を使用します。インデックスの使用 |
| | 1 | シンプル | イメージストーリー | 参照 | ストーリーID,ストーリーID_2 | ストーリーID | 4 | ストーリー.id | 1 | ヌル |
| | 1 | シンプル | 画像 | eq_ref | PRIMARY,position_id | プライマリ | 4 | image_story.image_id | 1 | ヌル |
+----+-------------+------------------+--------+-- -------------------------------+----------------------+------- --+-------------------------+---------------------+------------- -------------------------------------------+


+-----------------+------------+------------------ --+--------------+-------------+-----------+------ -------+----------+--------+------+------------+-- -------+---------------+
| | 表 | 表 一意でない | キー名 | Seq_in_index | 列名 | 照合 | カーディナリティ | サブパート | 梱包済み | ヌル | インデックスの種類 | コメント | 索引_コメント |
+-----------------+------------+------------------ --+--------------+-------------+-----------+------ -------+----------+--------+------+------------+-- -------+---------------+
| | 著者ストーリー | 0 | プライマリ | 1 | ID | あ | 220116 | ヌル | ヌル | | | Bツリー| | | | |
| | 著者ストーリー | 0 | 物語の作者 | 1 | ストーリーID | あ | 220116 | ヌル | ヌル | | | Bツリー| | | | |
| | 著者ストーリー | 0 | 物語の作者 | 2 | 著者ID | あ | 220116 | ヌル | ヌル | | | Bツリー| | | | |
| | 著者ストーリー | 1 | 著者ID | 1 | 著者ID | あ | 2179 | ヌル | ヌル | | | Bツリー| | | | |
| | 著者ストーリー | 1 | ストーリーID | 1 | ストーリーID | あ | 220116 | ヌル | ヌル | | | Bツリー| | | | |
| | イメージストーリー | 0 | プライマリ | 1 | ID | あ | 148902 | ヌル | ヌル | | | Bツリー| | | | |
| | イメージストーリー | 0 | ストーリー_イメージ | 1 | ストーリーID | あ | 148902 | ヌル | ヌル | | | Bツリー| | | | |
| | イメージストーリー | 0 | ストーリー_イメージ | 2 | image_id | あ | 148902 | ヌル | ヌル | | | Bツリー| | | | |
| | イメージストーリー | 1 | ストーリーID | 1 | ストーリーID | あ | 148902 | ヌル | ヌル | | | Bツリー| | | | |
| | イメージストーリー | 1 | image_id | 1 | image_id | あ | 148902 | ヌル | ヌル | | | Bツリー| | | | |
| | 分類 | 0 | プライマリ | 1 | ID | あ | 257 | ヌル | ヌル | | | Bツリー| | | | |
| | 分類 | 1 | ストーリーID | 1 | ストーリーID | あ | 257 | ヌル | ヌル | | | Bツリー| | | | |
| | 分類 | 1 | 名前 | 1 | 名前 | あ | 128 | ヌル | ヌル | | | Bツリー| | | | |
| | 分類 | 1 | 名前 | 2 | 位置 | あ | 257 | ヌル | ヌル | はい | Bツリー| | | | |
| | ストーリー | 0 | プライマリ | 1 | ID | あ | 962570 | ヌル | ヌル | | | Bツリー| | | | |
| | ストーリー | 1 | created_at | 1 | created_at | あ | 481285 | ヌル | ヌル | | | Bツリー| | | | |
| | ストーリー | 1 | ソース | 1 | ソース | あ | 4 | ヌル | ヌル | はい | Bツリー| | | | |
| | ストーリー | 1 | ソース ID | 1 | ソース ID | あ | 962570 | ヌル | ヌル | はい | Bツリー| | | | |
| | ストーリー | 1 | タイプ | 1 | タイプ | あ | 2 | ヌル | ヌル | | | Bツリー| | | | |
| | ストーリー | 1 | ステータス | 1 | ステータス | あ | 4 | ヌル | ヌル | | | Bツリー| | | | |
| | ストーリー | 1 | タイプ_ステータス | 1 | タイプ | あ | 2 | ヌル | ヌル | | | Bツリー| | | | |
| | ストーリー | 1 | タイプ_ステータス | 2 | ステータス | あ | 6 | ヌル | ヌル | | | Bツリー| | | | |
| | コメント | 0 | プライマリ | 1 | ID | あ | 232559 | ヌル | ヌル | | | Bツリー| | | | |
| | コメント | 1 | ステータス | 1 | ステータス | あ | 6 | ヌル | ヌル | | | Bツリー| | | | |
| | コメント | 1 | 日付 | 1 | 日付 | あ | 232559 | ヌル | ヌル | | | Bツリー| | | | |
| | コメント | 1 | ストーリーID | 1 | ストーリーID | あ | 29069 | ヌル | ヌル | | | Bツリー| | | | |
| | 画像 | 0 | プライマリ | 1 | ID | あ | 147206 | ヌル | ヌル | | | Bツリー| | | | |
| | 画像 | 0 | ソース ID | 1 | ソース ID | あ | 147206 | ヌル | ヌル | はい | Bツリー| | | | |
| | 画像 | 1 | 位置 | 1 | 位置 | あ | 4 | ヌル | ヌル | | | Bツリー| | | | |
| | 画像 | 1 | position_id | 1 | ID | あ | 147206 | ヌル | ヌル | | | Bツリー| | | | |
| | 画像 | 1 | position_id | 2 | 位置 | あ | 147206 | ヌル | ヌル | | | Bツリー| | | | |
| | ユーザー | 0 | プライマリ | 1 | ID | あ | 981 | ヌル | ヌル | | | Bツリー| | | | |
| | ユーザー | 0 | users_email_unique | 1 | 電子メール | あ | 981 | ヌル | ヌル | | | Bツリー| | | | |
+-----------------+------------+------------------ --+--------------+-------------+-----------+------ -------+----------+--------+------+------------+-- -------+---------------+



選択する
ストーリー。*、
count(comments.id) AS コメント、
GROUP_CONCAT(DISTINCT users.id ORDER BY users.id SEPARATOR ';') AS author_id,
GROUP_CONCAT(DISTINCT users.display_name ORDER BY users.id SEPARATOR ';') AS authors_display_name,
GROUP_CONCAT(DISTINCT users.url ORDER BY users.id SEPARATOR ';') AS authors_url,
GROUP_CONCAT(DISTINCT classifications2.name SEPARATOR ';') AS classifications_name,
GROUP_CONCAT(DISTINCT images.id ORDER BY images.position,images.id SEPARATOR ';') AS images_id,
GROUP_CONCAT(DISTINCT images.caption ORDER BY images.position,images.id SEPARATOR ';') AS images_caption,
GROUP_CONCAT(DISTINCT images.thumbnail ORDER BY images.position,images.id SEPARATOR ';') AS images_thumbnail,
GROUP_CONCAT(DISTINCT images.medium ORDER BY images.position,images.id SEPARATOR ';') AS images_medium,
GROUP_CONCAT(DISTINCT images.large ORDER BY images.position,images.id SEPARATOR ';') AS images_large
から
  分類
  INNER JOIN ストーリー
    ON stories.id = classifications.story_id
  LEFT JOIN 分類 AS 分類2
    ON stories.id = classifications2.story_id
  左結合のコメント
    オン stories.id = コメント.story_id
  LEFT JOIN image_story
    オン stories.id = image_story.story_id
  左結合画像
    ON images.id = image_story.`image_id`
 内部結合
    オン stories.id = author_story.story_id
 INNER JOIN ユーザー
    ON users.id = author_story.author_id
 WHERE classifications.`name` LIKE 'Home:Top%'
   AND ストーリー.ステータス = 1
GROUP BY stories.id
NULL 順

更新 2: 2013 年 4 月 14 日

もう一つ気がついた。stories.content(LONGTEXT) と(LONGTEXT) を選択しないとstories.content_html、クエリは0.015数秒から数秒に短縮され0.006ます。今のところ、私はそれらをなくすか、または何か他のものに置き換えることができるかどうかを検討contentcontent_htmlています.

上記の 2013 年 4 月 13 日の更新でクエリ、インデックス、および説明を更新しましたが、それらはマイナーで増分的なものだったため、今回の更新では再投稿しませんでした。クエリはまだ使用していfilesortます。私は取り除くことができませんが、取り除くことができGROUP BYましたORDER BY

更新 3: 2013 年 4 月 16 日

image_story要求に応じて、両方からstories_id INDEXES を削除しましたauthor_story。これらは冗長であるためです。その結果、explain の出力は変更されたことを示すためだけに変更されましたpossible_keysUsing Index残念ながら、それでも最適化は表示されませんでした。

また、クエリの実行時間に非常に大きな違いをもたらしているのではなく、フェッチするように変更LONGTEXTされました。TEXTLEFT(stories.content, 500)stories.content

+----+-------------+------------------+--------+-- ---------------------------+--------------+------- --+-------------------------+---------------------+------------- -------------------------------------------------- ------+
| | ID | select_type | テーブル | タイプ | 可能な_キー | キー | key_len | 参照 | 行 | 行 エクストラ |
+----+-------------+------------------+--------+-- ---------------------------+--------------+------- --+-------------------------+---------------------+------------- -------------------------------------------------- ------+
| | 1 | シンプル | 分類 | 参照 | story_id,name,name_position | 名前 | 102 | 定数 | 10 | インデックス条件の使用; where を使用します。一時的な使用; ファイルソートの使用 |
| | 1 | シンプル | ストーリー | eq_ref | プライマリ、ステータス | プライマリ | 4 | 分類.物語_id | 1 | where | の使用
| | 1 | シンプル | 分類2 | 参照 | ストーリーID | ストーリーID | 4 | ストーリー.id | 1 | where | の使用
| | 1 | シンプル | 著者ストーリー | 参照 | 物語の作者 | 物語の作者 | 4 | ストーリー.id | 1 | where を使用します。インデックスの使用 |
| | 1 | シンプル | ユーザー | eq_ref | プライマリ | プライマリ | 4 | author_story.author_id | 1 | where | の使用
| | 1 | シンプル | コメント | 参照 | ストーリーID | ストーリーID | 8 | ストーリー.id | 8 | where を使用します。インデックスの使用 |
| | 1 | シンプル | イメージストーリー | 参照 | ストーリー_イメージ | ストーリー_イメージ | 4 | ストーリー.id | 1 | インデックスの使用 |
| | 1 | シンプル | 画像 | eq_ref | PRIMARY,position_id | プライマリ | 4 | image_story.image_id | 1 | ヌル |
+----+-------------+------------------+--------+-- ---------------------------+--------------+------- --+-------------------------+---------------------+------------- -------------------------------------------------- ------+

innodb_buffer_pool_size
134217728

TABLE_NAME INDEX_LENGTH
image_story 10010624
image_story 4556800
image_story 0

TABLE_NAME INDEX_NAMES サイズ
夜明け/image_story story_image 13921
4

6 に答える 6

9

最適化の 2 つの機会がすぐにわかります。

OUTER JOIN を INNER JOIN に変更する

あなたのクエリは現在 434792 件の記事をスキャンしています。すべての記事が「Home:Top%」に一致する分類を持っているとは限らないと仮定すると、より適切に絞り込むことができるはずです。インデックスを使って探している分類を見つけてから、一致するストーリーを検索することをお勧めします。

ただしLEFT OUTER JOIN、分類に使用しています。つまり、一致する分類があるかどうかに関係なく、すべてのストーリーがスキャンされます。次に、句の分類に条件を付けることでそれを打ち負かし、WHEREパターンに一致する分類が存在することを事実上必須にしますLIKE。つまり、これはもはや外部結合ではなく、内部結合です。

分類テーブルを最初に配置して内部結合にすると、オプティマイザーはそれを使用して、一致する分類を持つストーリーだけにストーリーの検索を絞り込みます。

. . . 
FROM
  classifications
  INNER JOIN stories
    ON stories.id = classifications.story_id 
. . .

オプティマイザーは、テーブルの順序を変更するのが有利な場合を判断できると想定されているため、クエリで順序を変更する必要がない場合があります。INNER JOINただし、この場合は an を使用する必要があります。

複合インデックスを追加する

交差テーブル image_story と author_story には複合インデックスがありません。多くの場合、多対多の関係で交差テーブルに複合インデックスを追加することは大きな利点です。これにより、結合を実行して「インデックスを使用する」最適化を得ることができます。

ALTER TABLE image_story ADD UNIQUE KEY imst_st_im (story_id, image_id);
ALTER TABLE author_story ADD UNIQUE KEY aust_st_au (story_id, author_id);

コメントを更新して更新してください:

新しいインデックスを正しく作成したかどうかわかりません。インデックスのダンプには列が表示されず、更新された EXPLAIN によると、新しいインデックスは使用されていません。新しいインデックスを使用すると、EXPLAIN の余分なフィールドに "Using index" が表示され、パフォーマンスが向上します。

各テーブルの出力はSHOW CREATE TABLE、示したように、インデックスのダンプ (列名なし) よりも完全な情報になります。

インデックスを作成した後、これらのテーブルごとに ANALYZE TABLE を 1 回実行する必要がある場合があります。また、クエリを複数回実行して、インデックスがバッファー プールにあることを確認します。このテーブルは InnoDB ですか、それとも MyISAM ですか?

また、EXPLAIN の出力で、rows列に表示される行がはるかに少ないことに気付きました。それは改善です。

本当に必要ORDER BYですか?使用ORDER BY NULLすると、「ファイルソートの使用」を取り除くことができ、パフォーマンスが向上する可能性があります。


あなたの更新について:

image_storyおよびauthor_storyテーブルから「インデックスの使用」最適化がまだ得られていません。私が持っている1つの提案は、冗長なインデックスを排除することです:

ALTER TABLE image_story DROP KEY story_id;
ALTER TABLE author_story DROP KEY story_id;

その理由は、story_id の単一列インデックスの恩恵を受ける可能性のあるクエリは、(story_id,image_id) の 2 列インデックスの恩恵を受けることもできるからです。冗長なインデックスを削除すると、オプティマイザーがより適切な決定を下すのに役立ちます (スペースを節約することもできます)。これはpt-duplicate-key-checker のようなツールの背後にある理論です。

また、バッファー プールがインデックスを保持するのに十分な大きさであることも確認します。クエリ中にインデックスがバッファー プールに対してページ インおよびページ アウトすることは望ましくありません。

SHOW VARIABLES LIKE 'innodb_buffer_pool_size'

image_story テーブルのインデックスのサイズを確認します。

SELECT TABLE_NAME, INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES 
WHERE TABLE_NAME = 'image_story';

そして、それを現在バッファプールに存在しているインデックスの量と比較してください:

SELECT TABLE_NAME, GROUP_CONCAT(DISTINCT INDEX_NAME) AS INDEX_NAMES, SUM(DATA_SIZE) AS SIZE 
FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU 
WHERE TABLE_NAME = '`test`.`image_story`' AND INDEX_NAME <> 'PRIMARY'

もちろん、上記の「test」は、テーブルが属するデータベース名に変更してください。

その information_schema テーブルは、MySQL 5.6 で新しく追加されました。EXPLAIN が MySQL 5.6 の新機能である「Using index condition」を示しているため、MySQL 5.6 を使用していると思います。

非常に長い文字列を記述する必要がない限り、LONGTEXT はまったく使用しません。次の点に注意してください。

  • TEXT は最大 64KB を保持します
  • MEDIUMTEXT は最大 16MB を保持します
  • LONGTEXT は最大 4GB まで保持
于 2013-04-12T03:18:09.203 に答える
8

MYSQL を使用しているため、以下を利用できます。Straight_join

STRAIGHT_JOIN forces the optimizer to join the tables in the order in which they are listed in the FROM clause. You can use this to speed up a query if the optimizer joins the tables in nonoptimal order

storiesまた、ステータス1のデータのみが必要なため、テーブルのデータをフィルタリングすることも改善の1つの範囲です

したがって、フォーム句では、テーブル全体をstories追加するのではなく、必要なレコードのみを追加します。これは、クエリプランが434792行があり、classificationテーブルにも同じことが示されているためです。

FROM
   (SELECT 
       * 
   FROM
       STORIES
   WHERE 
       STORIES.status = 1) stories
LEFT JOIN
   (SELECT 
       * 
   FROM
       classifications
   WHERE
       classifications.`name` LIKE 'Home:Top%') classifications
ON stories.id = classifications.story_id 

また、およびsort_buffer_sizeとして示されているように増やすことができるもう 1 つの提案ですが、セッションごとにバッファーのサイズが大きくなるため、バッファー サイズを大きくするように注意してください。order bygroup by

order byまた、可能であれば、節を削除すると元の時間の一部だけが改善されると述べたので、可能であればアプリケーションでレコードを注文できます1/6...

編集

これらの列は結合に使用されるため、 image_story.image_idfor image_storytable およびauthor_story.story_idfor tableにインデックスを追加しますauthor_story

また、使用中にインデックスをimages.position, images.id作成する必要があります。

編集 16/4

更新を見て、クエリをほぼ最適化したと思います...

BillKarwinが述べたように、改善できる場所の1つは適切なデータ型を使用することです...ステータスやその他の成長の範囲を持たない列に使用ENUMまたは入力できます。クエリのパフォーマンスを最適化するのに役立ち、またTINYINTあなたのテーブルのストレージ性能....

お役に立てれば....

于 2013-04-11T15:45:20.557 に答える
6

コンピューティング

GROUP_CONCAT(DISTINCT classifications2.name SEPARATOR ';')

classificationsは大きなテーブルであり、すべての結合のために処理する行数が倍増するため、おそらく最も時間のかかる操作です。

したがって、その情報には一時テーブルを使用することをお勧めします。また、LIKE 条件を 2 回 (一時テーブルに対して 1 回、「実際の」クエリに対して 1 回) 計算するのを避けるために、そのための一時テーブルも作成します。

非常に単純化されたバージョンの元のクエリは次のとおりです(読みやすいように画像とユーザーのテーブルはありません)。

SELECT
    stories.*,
    count(DISTINCT comments.id) AS comments,
    GROUP_CONCAT(DISTINCT classifications2.name ORDER BY 1 SEPARATOR ';' )
        AS classifications_name
FROM
    stories
    LEFT JOIN classifications
        ON stories.id = classifications.story_id
    LEFT JOIN classifications AS classifications2
        ON stories.id = classifications2.story_id
    LEFT JOIN comments
        ON stories.id = comments.story_id
WHERE
    classifications.`name` LIKE 'Home:Top%'
        AND stories.status = 1
GROUP BY stories.id
    ORDER BY stories.id, classifications.`name`, classifications.`positions`;

これを次のクエリに置き換えます。一時テーブル_tmp_filtered_classifications(LIKE Home:Top% という名前の分類の ID) と_tmp_classifications_of_story(各ストーリー ID に「含まれる」_tmp_filtered_classifications、すべての分類名)。

DROP TABLE IF EXISTS `_tmp_filtered_classifications`;

CREATE TEMPORARY TABLE _tmp_filtered_classifications
    SELECT id FROM classifications WHERE name LIKE 'Home:Top%';

DROP TABLE IF EXISTS `_tmp_classifications_of_story`;

CREATE TEMPORARY TABLE _tmp_classifications_of_story ENGINE=MEMORY
    SELECT stories.id AS story_id, classifications2.name
        FROM 
        _tmp_filtered_classifications
        INNER JOIN classifications        
            ON _tmp_filtered_classifications.id=classifications.id
        INNER JOIN stories
            ON stories.id = classifications.story_id
        LEFT JOIN classifications AS classifications2
            ON stories.id = classifications2.story_id
        GROUP BY 1,2;

SELECT
    stories.*,
    count(DISTINCT comments.id) AS comments,
    GROUP_CONCAT(DISTINCT classifications2.name ORDER BY 1 SEPARATOR ';')
        AS classifications_name
FROM
    _tmp_filtered_classifications
    INNER JOIN classifications        
        ON _tmp_filtered_classifications.id=classifications.id
    INNER JOIN stories
        ON stories.id = classifications.story_id
    LEFT JOIN _tmp_classifications_of_story AS classifications2
        ON stories.id = classifications2.story_id
    LEFT JOIN comments
        ON stories.id = comments.story_id
WHERE
    stories.status = 1
GROUP BY stories.id
    ORDER BY stories.id, classifications.`name`, classifications.`positions`;

両方のクエリが同じ結果を提供することを確認するために、クエリに「order by」句を追加したことに注意してください (diff を使用)。また、クエリが計算するコメントの数が間違っているように変更count(comments.id)しました(これも、行数を乗算する結合のためです)。count(DISTINCT comments.id)

于 2013-04-11T14:26:04.450 に答える
0

実験するデータの詳細をすべて把握しているわけではありませんが、一致するデータ量が最も少ない操作を最初に実行し、その後の操作で大量のデータを排除する必要があることは知っています。

クエリ全体の複雑さによっては、この方法で操作を並べ替えることができない場合があります。ただし、2 つの個別のクエリを実行することもできます。最初のクエリでは、明らかに必要とされないデータを除外し、その結果を 2 番目のクエリにフィードします。他の誰かが一時テーブルの使用を提案しましたが、それはその状況を処理する良い方法です。

この戦略について説明が必要な場合は、お知らせください。

** 更新: 各操作が他の操作とほぼ同じ割合のデータに一致する場合に使用される同様の戦術は、各操作を個別に時間を計ってから、最も時間がかからない操作を最初に実行することです。一部の検索操作は他の操作よりも高速であり、他のすべての要素が等しい場合、最速の操作が最初に実行されます。このように、低速の検索操作では処理するデータが少なくなり、全体的な結果としてパフォーマンスが向上します。

于 2013-04-12T00:38:42.543 に答える
0

ここで試すことができるいくつかの方法:

1) create covering index on classifications.`name`

カバリング インデックスを作成することで、クエリを高速化できます。

カバリング インデックスとは、クエリで選択されたすべてのフィールドがインデックスによってカバーされる場合を指します。その場合、InnoDB (MyISAM ではない) はテーブル内のデータを読み取ることはなく、インデックス内のデータのみを使用するため、処理が大幅に高速化されます。選択する。

CREATE TABLE classifications( KEY class_name( name,...すべての列) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

classifications.name LIKE 'Home:Top%' 2)使用する代わりにlocate('Home:Top',classifications.name)

于 2013-04-17T13:08:05.440 に答える