4

MySQL クエリのパフォーマンスに問題があります。

テーブル (InnoDB):

+--------------------+---------------------+------+-----+-------------------+-------+
| Field              | Type                | Null | Key | Default           | Extra |
+--------------------+---------------------+------+-----+-------------------+-------+
| st_resource_id     | varchar(32)         | NO   | MUL | NULL              |       |
| st_sub_resource_id | varchar(32)         | YES  |     | NULL              |       |
| st_title           | varchar(500)        | YES  |     | NULL              |       |
| st_resource_type   | varchar(100)        | NO   | MUL | NULL              |       |
| st_site_id         | tinyint(4)          | NO   | MUL | NULL              |       |
| st_time            | timestamp           | NO   | MUL | CURRENT_TIMESTAMP |       |
| st_user_id         | int(10) unsigned    | YES  |     | NULL              |       |
| st_full_access     | tinyint(1) unsigned | YES  |     | NULL              |       |
+--------------------+---------------------+------+-----+-------------------+-------+

インデックス:

+---------------+------------+------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table         | Non_unique | Key_name         | Seq_in_index | Column_name        | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------------+------------+------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+
| nr_statistics |          1 | resource_id      |            1 | st_resource_id     | A         |     1546165 |     NULL | NULL   |      | BTREE      |         |
| nr_statistics |          1 | resource_id      |            2 | st_sub_resource_id | A         |     1546165 |     NULL | NULL   | YES  | BTREE      |         |
| nr_statistics |          1 | st_time          |            1 | st_time            | A         |     1546165 |     NULL | NULL   |      | BTREE      |         |
| nr_statistics |          1 | st_site_id       |            1 | st_site_id         | A         |          16 |     NULL | NULL   |      | BTREE      |         |
| nr_statistics |          1 | st_resource_type |            1 | st_resource_type   | A         |          16 |       10 | NULL   |      | BTREE      |         |
+---------------+------------+------------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+

クエリ:

SELECT st_resource_id AS docId, count(*) AS cnt
FROM nr_statistics
WHERE
  st_resource_type = 'document'
  AND st_sub_resource_id = 'text'
  AND st_time > DATE_SUB(NOW(), INTERVAL 7 DAY)
  AND st_site_id = 1
GROUP BY st_resource_id
ORDER BY cnt DESC
LIMIT 0, 5;

クエリ プラン:

+----+-------------+---------------+-------+-------------------------------------+-------------+---------+------+---------+----------------------------------------------+
| id | select_type | table         | type  | possible_keys                       | key         | key_len | ref  | rows    | Extra                                        |
+----+-------------+---------------+-------+-------------------------------------+-------------+---------+------+---------+----------------------------------------------+
|  1 | SIMPLE      | nr_statistics | index | st_time,st_site_id,st_resource_type | resource_id | 197     | NULL | 1581044 | Using where; Using temporary; Using filesort |
+----+-------------+---------------+-------+-------------------------------------+-------------+---------+------+---------+----------------------------------------------+

テーブルには最大 1,666,383 行あります。クエリの実行が非常に遅くなります。MySQL プロセス リストで、このクエリが "copy to tmp table phase" で長時間 (> 1 分) 表示されます。クエリは重い I/O 負荷を生成します。問題を修正してクエリの実行を高速化するために何をすべきかわかりません。

問題が間違ったインデックスの結果である場合、どのインデックスが正しいのでしょうか?

アップデート。新しい複合インデックスを作成しました:

| nr_statistics |          1 | st_site_id_2     |            1 | st_site_id         | A         |          16 |     NULL | NULL   |      | BTREE      |         |
| nr_statistics |          1 | st_site_id_2     |            2 | st_resource_type   | A         |          16 |     NULL | NULL   |      | BTREE      |         |
| nr_statistics |          1 | st_site_id_2     |            3 | st_sub_resource_id | A         |      752018 |     NULL | NULL   | YES  | BTREE      |         |
| nr_statistics |          1 | st_site_id_2     |            4 | st_time            | A         |     1504037 |     NULL | NULL   |      | BTREE      |         |
| nr_statistics |          1 | st_site_id_2     |            5 | st_resource_id     | A         |     1504037 |     NULL | NULL   |      | BTREE      |         |

現在、クエリプランは次のとおりです。

+----+-------------+---------------+-------+---------------+--------------+---------+------+-------+-----------------------------------------------------------+
| id | select_type | table         | type  | possible_keys | key          | key_len | ref  | rows  | Extra                                                     |
+----+-------------+---------------+-------+---------------+--------------+---------+------+-------+-----------------------------------------------------------+
|  1 | SIMPLE      | nr_statistics | range | st_site_id_2  | st_site_id_2 | 406     | NULL | 21168 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+---------------+-------+---------------+--------------+---------+------+-------+-----------------------------------------------------------+

クエリは非常に高速 (0.0x 秒) で実行されるようになりましたが、新しいインデックスを強制的に使用する必要があります。

SELECT st_resource_id as docId, count( * ) AS Cnt
FROM nr_statistics
USE INDEX (st_site_id_2)
WHERE st_resource_type = 'document'
AND st_sub_resource_id = 'text'
AND st_time > DATE_SUB( NOW( ) , INTERVAL 7 DAY )
AND st_site_id = 1
GROUP BY st_resource_id
ORDER BY cnt DESC
LIMIT 0 , 5;

問題は解決されましたが (美しくはありませんが効果的な方法です)、未解決の質問がいくつかあります (コメントを参照)。

4

3 に答える 3

2

に複合インデックスを作成します(st_site_id, st_resource_type, st_sub_resourse_id, st_time, st_resource_id)

ただし、索引付けできないものを注文しているため、計画にはまだtemporaryと があります。filesortCOUNT(*)

このクエリを高速かつ頻繁に実行する必要がある場合は、サイト/リソース/サブリソース/週の組み合わせごとにカウントを格納し、トリガーで更新する集計テーブルを作成する必要があります。

于 2012-06-01T12:32:02.537 に答える
1

で複合インデックスを作成しようとしましたst_resource_type, st_resource_id, st_time and st_site_idか? いくつかのインデックスがあるように見えますが、ほとんどは 1 つの列、または 2 つの列にあります。必要な列を多く含む複合インデックスを使用すると、パフォーマンスが向上する場合があります。

于 2012-06-01T12:31:27.810 に答える
0

複数の where 句を使用してクエリを実行する場合、それらを記述する順序は、クエリを記述した順序と一致する必要があります。

あなたの特定のケースでは、次のようになります。

CREATE INDEX stats_index ON nr_statistics (st_resource_type, st_sub_resource_id, st_time, st_site_id);

これにより、かなりのスピードブーストが得られるはずです。

于 2012-06-01T21:19:38.790 に答える