7

次のクエリがあります。

SELECT DISTINCT f1.match_static_id,
                f2.comments_no,
                f2.maxtimestamp,
                users.username,
                users.id,
                matches_of_comments.localteam_name,
                matches_of_comments.visitorteam_name,
                matches_of_comments.localteam_goals,       
                matches_of_comments.visitorteam_goals,
                matches_of_comments.match_status,
                new_iddaa.iddaa_code
FROM comments AS f1
INNER JOIN (
             SELECT match_static_id,
                    MAX( TIMESTAMP ) maxtimestamp,
                    COUNT( match_static_id ) AS comments_no
             FROM comments
             GROUP BY match_static_id
          ) AS f2 ON f1.match_static_id = f2.match_static_id 
                  AND f1.timestamp = f2.maxtimestamp
INNER JOIN users ON users.id = f1.user_id
INNER JOIN matches_of_comments ON matches_of_comments.match_id = f2.match_static_id
LEFT JOIN new_iddaa ON new_iddaa.match_id = matches_of_comments.match_id
WHERE matches_of_comments.flag =1
ORDER BY f2.maxtimestamp DESC

これは、そのクエリの EXPLAIN プランです。

+----+-------------+---------------------+--------+-----------------------------------+-----------+---------+------------------------------------------+-------+------------------------------------------------+
| id | select_type |        table        |  type  |           possible_keys           |    key    | key_len |                   ref                    | rows  |                     extra                      |
+----+-------------+---------------------+--------+-----------------------------------+-----------+---------+------------------------------------------+-------+------------------------------------------------+
|  1 | PRIMARY     | <derived2>          | ALL    | NULL                              | NULL      | NULL    | NULL                                     |   542 | Using temporary; Using filesort                |
|  1 | PRIMARY     | f1                  | ref    | timestamp,match_static_id,user_id | timestamp | 4       | f2.maxtimestamp                          |     1 | Using where                                    |
|  1 | PRIMARY     | users               | eq_ref | PRIMARY                           | PRIMARY   | 4       | skormix_db1.f1.user_id                   |     1 |                                                |
|  1 | PRIMARY     | matches_of_comments | ALL    | match_id                          | NULL      | NULL    | NULL                                     | 20873 | Range checked for each record (index map: 0x8) |
|  1 | PRIMARY     | new_iddaa           | ref    | match_id                          | match_id  | 4       | skormix_db1.matches_of_comments.match_id |     1 |                                                |
|  2 | DERIVED     | comments            | ALL    | NULL                              | NULL      | NULL    | NULL                                     |   933 | Using temporary; Using filesort                |
+----+-------------+---------------------+--------+-----------------------------------+-----------+---------+------------------------------------------+-------+------------------------------------------------+

この一致に少なくとも 1 つのコメントがある場合、このクエリを使用して一致情報を取得します。
チームの名前、コード (iddaa コード)、コメント数、最後のコメントのタイムスタンプ、最後のコメントの作成者を取得します。
私は大きなデータベースを持っており、今後数か月でさらに大きくなると予想されます。また、MySQL クエリを初めて使用するので、最初から最適化クエリを使用していることを確認したいので、読み方を知りたいです。これは、クエリをより適切かつ高速にするための情報を説明します。

作成したにもかかわらず、インデックスを使用していないテーブルの場所がたくさんあることがわかりました。
テーブル列にも派生が表示されますが、派生クエリのインデックスを作成できないため、このクエリをより高速にする方法とファイルソートを取り除く方法がわかりません??

インデックス (キー) を使用して、クエリ内の using テーブルの構造を書き留めます。質問に対するヒントや簡単な回答が得られることを願っています。事前に感謝します。

コメント (f1) テーブル構造は次のとおりです。

CREATE TABLE `comments` (
 `id` int(25) NOT NULL AUTO_INCREMENT,
 `comments` text COLLATE utf8_unicode_ci NOT NULL,
 `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 `date` date NOT NULL,
 `time` time NOT NULL,
 `match_static_id` int(25) NOT NULL,
 `ip` varchar(255) CHARACTER SET latin1 NOT NULL,
 `comments_yes_or_no` int(25) NOT NULL,
 `user_id` int(25) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `timestamp` (`timestamp`),
 KEY `match_static_id` (`match_static_id`),
 KEY `user_id` (`user_id`)
) ENGINE=MyISAM AUTO_INCREMENT=935 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

users テーブル構造は次のとおりです。

CREATE TABLE `users` (
 `id` int(25) NOT NULL AUTO_INCREMENT,
 `username` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `gender` int(25) NOT NULL,
 `first_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `last_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `avatar` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `alert` int(25) NOT NULL,
 `daily_tahmin` int(25) NOT NULL,
 `monthly_tahmin` int(25) NOT NULL,
 `admin` int(25) NOT NULL,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=995 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

matches_of_comments_ 構造は次のとおりです。

CREATE TABLE `matches_of_comments` (
 `id` int(25) NOT NULL AUTO_INCREMENT,
 `en_tournament_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `tournament_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `country_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `match_status` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `match_time` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `match_date` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `static_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `fix_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `match_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `localteam_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `localteam_goals` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `localteam_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `visitorteam_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `visitorteam_goals` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `visitorteam_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `ht_score` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `flag` int(25) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `match_status` (`match_status`),
 KEY `match_date` (`match_date`),
 KEY `match_id` (`match_id`),
 KEY `localteam_id` (`localteam_id`),
 KEY `visitorteam_id` (`visitorteam_id`),
 KEY `flag` (`flag`)
) ENGINE=MyISAM AUTO_INCREMENT=237790 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

new_iddaa テーブル構造は次のとおりです。

CREATE TABLE `new_iddaa` (
 `id` int(25) NOT NULL AUTO_INCREMENT,
 `match_id` int(25) NOT NULL,
 `iddaa_code` int(25) NOT NULL,
 `tv_channel` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
 `skormix_tahmin` varchar(255) CHARACTER SET utf8 NOT NULL,
 PRIMARY KEY (`id`),
 KEY `match_id` (`match_id`)
) ENGINE=MyISAM AUTO_INCREMENT=8191 DEFAULT CHARSET=latin1
4

5 に答える 5

1

オプションについて議論する前に、より差し迫った問題から始めます。


最初の問題は次のとおりです。

SELECT DISTINCT …

Aselect distinctは遅いです。非常に遅い: 基本的に、セットから返された各行の各フィールドを比較します。行ごとに一意であることが保証されている がある場合、最適化の余地は当然ありIDますが、独自のクエリはそのような可能性を提供しているようには見えません: せいぜいmatches_of_commentsとからのタプルnew_iddaaです。

これを回避するには、クエリを 2 つ以上の部分に分割し、実際に必要なものだけをフェッチします。これはmatches_of_comments、最新のコメント日付で並べ替え、 と から追加の化粧品データを取得しusersているようnew_iddaaです。

次は私見の最大の問題です:

INNER JOIN (
         SELECT match_static_id,
                MAX( TIMESTAMP ) maxtimestamp,
                COUNT( match_static_id ) AS comments_no
         FROM comments
         GROUP BY match_static_id
      ) AS f2 ON f1.match_static_id = f2.match_static_id 
              AND f1.timestamp = f2.maxtimestamp

(match_static_id, timestamp)インデックスを持たないタプルのテーブルと集計を結合し、その上で巨大なセットをフェッチしています。将来的にマージ結合が保証されますが、これは望んだものではありません。

最後の目を見張るような問題は次のとおりです。

ORDER BY f2.maxtimestamp DESC

まず、そこに制限はありません。これは、膨大なセットを構築、ソート、および返すことを意味します。確かにこのデータのページネーションを行っているので、クエリで limit 句を追加してページネーションを行ってください。

制限を追加したら、余分な行を追加しているものと、それらをどのように並べるかを検討する必要があります。あなたのスキーマに基づいて、そうすると思いますnew_iddaa。後者の情報がそのクエリの一部であり、それが返す行数である必要があるような方法で物事をページ付けしていますか? これらの行がどのようにソートされるかに明らかに興味がないので、そうではないと思います。

スキーマをスキャンした後、この追加のスキーマが表示されます:

`match_id` varchar(255)

これを参照する行は整数ですよね?したがって、varchar を int に、またはその逆にキャストするオーバーヘッドを回避し、どちらの場合でもインデックスを使用できるようにするために、整数でもある必要があります。

この特定のクエリには関係ありませんが、次の 2 つのフィールドにも注意を払い、適切にキャストする必要があります。

`tournament_id` varchar(255)
`match_time` varchar(255)
`match_date` varchar(255)
`static_id` varchar(255)
`fix_id` varchar(255)
`localteam_id` varchar(255)
`visitorteam_id` varchar(255)

クエリの改善について…</p>

私がそれを読んだとき、あなたはmatches_of_comments最新のコメントで注文しています。コメントの数も必要なので、それを行うことから始めます。多くのページのうち最初の 10 件をページ付けすると仮定すると、クエリは次のようになります。

SELECT match_static_id,
       MAX( TIMESTAMP ) maxtimestamp,
       COUNT( match_static_id ) AS comments_no
FROM comments
GROUP BY match_static_id
ORDER BY maxtimestamp DESC
LIMIT 10 OFFSET 0

それで全部です。

10 個の ID が提供されますが、制限を増やすとさらに多くなります。アプリでそれらをループし、in (…)必要に応じて他のテーブルから個々のデータを取得できる句を作成します。これは 1 つまたは複数のクエリで実行できますが、ほとんど問題になりません。ポイントは、その集計での結合を避けることです。これにより、後続のクエリでインデックスを使用できるようになります。


上記のクエリを完全に削除することで、さらに劇的に改善することができます。

そのためには、 、、およびの 3 つのフィールドをmatches_of_commentsに追加します。トリガーを使用してそれらを維持し、 にインデックスを追加します。これにより、代わりに次の効率的なクエリを実行できます。last_comment_timestamplast_comment_user_idnum_comments(flag, last_comment_timestamp)

SELECT matches_of_comments.static_id,
       matches_of_comments.num_comments,
       matches_of_comments.last_comment_timestamp,
       matches_of_comments.last_comment_user_id,
       matches_of_comments.localteam_name,
       matches_of_comments.visitorteam_name,
       matches_of_comments.localteam_goals,       
       matches_of_comments.visitorteam_goals,
       matches_of_comments.match_status
FROM matches_of_comments
WHERE matches_of_comments.flag = 1
ORDER BY matches_of_comments.last_comment_timestamp DESC
LIMIT 10 OFFSET 0

次に、必要なデータのみをusersandから選択する必要があります —既に説明したように、句new_iddaaを含む個別のクエリを使用します。in (…)

于 2013-11-22T17:31:08.763 に答える
0

分析機能を使用しました。しかし、テストするデータがないため、これが最適かどうかはよくわかりません

SELECT * 
FROM
(
    SELECT DISTINCT f1.match_static_id,
                    users.username,
                    users.id,
                    matches_of_comments.localteam_name,
                    matches_of_comments.visitorteam_name,
                    matches_of_comments.localteam_goals,       
                    matches_of_comments.visitorteam_goals,
                    matches_of_comments.match_status,
                    new_iddaa.iddaa_code,
                    @MAX_TIMESTAMP AS `FIRST_VALUE(MATCH_STATIC_ID) OVER(partition by f1.match_static_id ORDER BY F1.TIMESTAMP DESC)`,
                    @COMMENTS_NO AS `COUNT(1) OVER(partition by f1.match_static_id)`,
                    F1.TIMESTAMP
    FROM comments AS f1
    INNER JOIN users ON users.id = f1.user_id
    INNER JOIN matches_of_comments 
    ON matches_of_comments.match_id = f1.match_static_id
    AND matches_of_comments.flag =1
    LEFT JOIN new_iddaa 
    ON new_iddaa.match_id = matches_of_comments.match_id
) A
WHERE @MAX_TIMESTAMP = TIMESTAMP
ORDER BY @MAX_TIMESTAMP DESC
于 2013-11-22T03:22:48.643 に答える