私はここで迷っています。このクエリが完了するまでに約50秒かかるため、遅すぎると思います。これがクエリです。 db.r3.large
で実行されているAmazon RDSのMySQLとMySQLバージョンMySQL 5.7.17
を使用します
SELECT bucket_label AS bid,
Count(user_id) AS c,
Count(DISTINCT user_id) AS cu
FROM event_impression
WHERE context = 'PROD'
AND experiment_id = Unhex(Replace("18454a99-ada6-41a8-b192-bcd3d5c514cb",
"-",
""))
AND timestamp >= '2018-04-08 22:21:04'
AND timestamp <= '2018-04-10 22:21:04'
GROUP BY bucket_label;
ここにインデックスがあります
mysql> show index from event_impression;
+------------------+------------+-------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------------+------------+-------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| event_impression | 1 | user_id | 1 | user_id | A | 3248866 | NULL | NULL | | BTREE | | |
| event_impression | 1 | experiment_id | 1 | experiment_id | A | 4305 | NULL | NULL | | BTREE | | |
| event_impression | 1 | bucket_label | 1 | bucket_label | A | 7108 | NULL | NULL | | BTREE | | |
| event_impression | 1 | timestamp | 1 | timestamp | A | 3315621 | NULL | NULL | | BTREE | | |
| event_impression | 1 | event_impression_ibfk_1 | 1 | experiment_id | A | 2914 | NULL | NULL | | BTREE | | |
| event_impression | 1 | event_impression_ibfk_1 | 2 | bucket_label | A | 9619 | NULL | NULL | | BTREE | | |
+------------------+------------+-------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
6 rows in set (0.01 sec)
これがテーブルスキーマです
mysql> describe event_impression;
+---------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------------+------+-----+---------+-------+
| user_id | varchar(200) | NO | MUL | NULL | |
| experiment_id | varbinary(16) | NO | MUL | NULL | |
| bucket_label | varchar(64) | NO | MUL | NULL | |
| timestamp | datetime | NO | MUL | NULL | |
| payload | varchar(4096) | YES | | NULL | |
| context | varchar(200) | YES | | PROD | |
+---------------+---------------+------+-----+---------+-------+
6 rows in set (0.01 sec)
そして、これがそのクエリの結果です
mysql> select bucket_label as bid,
-> count(user_id) as c,
-> count(distinct user_id) as cu
-> from wasabi.event_impression
-> where context = 'PROD'
-> and experiment_id = UNHEX(REPLACE("18454a99-ada6-41a8-b192-bcd3d5c514cb", "-",""))
-> and timestamp >= '2018-04-08 22:21:04'
-> and timestamp <= '2018-04-10 22:21:04'
-> group by bucket_label;
+---------+--------+-------+
| bid | c | cu |
+---------+--------+-------+
| 1 | 294308 | 22403 |
| 1_1 | 185561 | 14703 |
| 2_1 | 267417 | 22183 |
| 2_2 | 284134 | 21945 |
+---------+--------+-------+
4 rows in set (41.22 sec)
このクエリを改善するための提案はあります。または、設定を確認したい場合もお知らせください。
これはテーブルの大きさです
mysql> select count(*) from event_impression;
+----------+
| count(*) |
+----------+
| 40955148 |
+----------+
1 row in set (10.88 sec)
これはEXPLAIN
です
+----+-------------+------------------+------------+------+--------------------------------------------------------------+-------------------------+---------+-------+----------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+------+--------------------------------------------------------------+-------------------------+---------+-------+----------+----------+------------------------------------+
| 1 | SIMPLE | event_impression | NULL | ref | experiment_id,bucket_label,timestamp,event_impression_ibfk_1 | event_impression_ibfk_1 | 18 | const | 14958978 | 1.43 | Using index condition; Using where |
+----+-------------+------------------+------------+------+--------------------------------------------------------------+-------------------------+---------+-------+----------+----------+------------------------------------+
1 row in set, 1 warning (0.16 sec)
編集する
explain select bucket_label as bid,
count(user_id) as c,
count(distinct user_id) as cu
from wasabi.event_impression
where context = 'PROD'
and experiment_id = UNHEX(REPLACE("18454a99-ada6-41a8-b192-bcd3d5c514cb", "-",""))
and timestamp >= '2018-04-08 22:21:04'
and timestamp <= '2018-04-10 22:21:04'
group by bucket_label;
'1', 'SIMPLE', 'event_impression', NULL, 'ref', 'experiment_id,bucket_label,timestamp,event_impression_ibfk_1', 'event_impression_ibfk_1', '18', 'const', '14551230', '1.32', 'Using index condition; Using where'
[〜#〜]編集[〜#〜]
Whereステートメントを切り替えて、先頭にタイムスタンプを付けます。
explain select bucket_label as bid,
count(user_id) as c,
count(distinct user_id) as cu
from wasabi.event_impression
where timestamp BETWEEN '2018-04-08 22:21:04' AND '2018-04-10 22:21:04'
AND context = 'PROD'
AND experiment_id = UNHEX(REPLACE("18454a99-ada6-41a8-b192-bcd3d5c514cb", "-",""))
group by bucket_label;
+----+-------------+------------------+------------+------+--------------------------------------------------------------+-------------------------+---------+-------+----------+----------+------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------------+------------+------+--------------------------------------------------------------+-------------------------+---------+-------+----------+----------+------------------------------------+
| 1 | SIMPLE | event_impression | NULL | ref | experiment_id,bucket_label,timestamp,event_impression_ibfk_1 | event_impression_ibfk_1 | 18 | const | 16274608 | 1.22 | Using index condition; Using where |
+----+-------------+------------------+------------+------+--------------------------------------------------------------+-------------------------+---------+-------+----------+----------+------------------------------------+
mysql> show index from wasabi.event_impression;
+------------------+------------+-------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+------------------+------------+-------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| event_impression | 1 | user_id | 1 | user_id | A | 3836266 | NULL | NULL | | BTREE | | |
| event_impression | 1 | experiment_id | 1 | experiment_id | A | 5083 | NULL | NULL | | BTREE | | |
| event_impression | 1 | bucket_label | 1 | bucket_label | A | 8393 | NULL | NULL | | BTREE | | |
| event_impression | 1 | timestamp | 1 | timestamp | A | 3915091 | NULL | NULL | | BTREE | | |
| event_impression | 1 | event_impression_ibfk_1 | 1 | experiment_id | A | 3441 | NULL | NULL | | BTREE | | |
| event_impression | 1 | event_impression_ibfk_1 | 2 | bucket_label | A | 11358 | NULL | NULL | | BTREE | | |
+------------------+------------+-------------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
6 rows in set (0.01 sec)
WHERE
の_=
_部分でインデックスを開始し、次に「範囲」を1つ追加します。
_INDEX(context, experiment_id, -- in either order
timestamp)
_
これにより、クエリの実行が速くなります。
More 最適なインデックスの作成について。
注:「複合」インデックスは、複数の単一列インデックスを持つことと同じではありません。
「カバリング」インデックスはかさばりますが、少し高速に実行できます。
_INDEX(context, experiment_id, -- in either order
timestamp,
bucket_label, user_id) -- in either order
_
Donotput timestamp
first。
インデックスの使用は左から右に機能します。行をスキャンすると、インデックスの最初の列で可能なことを実行してから、次の列に移動します。
最初の列が_=
_(たとえば、_context = 'PROD'
_)でテストされている場合、インデックス内の隣接するallと一致する行、および次の行列は便利です。
最初の列が「範囲」でテストされる場合(たとえば、_timestamp BETWEEN ... AND ...
_)、次の列は役に立たなくなります。したがって、オプティマイザーは最初の範囲で停止します。
おなじみの例...最初に姓でソートされた人のリストがあるとします。そして、「Dave Poole」を検索します。
_INDEX(last, first)
_
私は少し気まぐれがあると思う
_WHERE first = 'Dave'
AND last = 'Poole' -- (in either order)
_
しかし今、クエリが
_WHERE first LIKE 'D%' -- (this is one form of "range")
AND last = 'Poole'
_
これは効率的であることがわかります-BTreeをドリルダウンして「Pooles」の長いリストにDがある場所までドリルダウンし、次に前方にスキャンします。
一方、どうですか
_WHERE first = 'Dave'
AND last LIKE 'P%'
_
では、どのようにしてエントリを見つけますか?まあ、P ...が始まる場所までBTreeをすばやくドリルダウンできますが、姓がPで始まるエントリのallをスキャンする必要があります。より効率的な方法があります。それ。
(もちろん、INDEX(first, last)
があると効率的です。)
選択性/カーディナリティについては...
last
またはfirst
よりも優れています。last
の「P」の選択性しか使用できないため、最悪のケースになります。したがって、2018年からは...(timestamp
)はPROD + abcd + 2018(推奨するインデックス)よりも劣ります。
カーディナリティが高いほど、インデックスの選択性が高くなります。 event_impression_ibfk_1はExperiment_idとbucket_labelで使用されており、どちらも特に選択的ではないようです。
Explain Planを正しく読んでいると、1490万行または4,000万行のテーブルをスキャンする必要があると思います。静かな時間、またはできればダウンタイムがある場合は、実行する価値があるかもしれません
ANALYZE TABLE event_impression
これは、テーブルの分散統計が最新であることを確認し、クエリオプティマイザーを支援するためです。このようなコマンドを実行するための物理リソースがあることを確認してください。CPUとディスクにかなりの負荷がかかります
テーブルに一意のフィールドの組み合わせがありますか?その場合、これにより、InnoDBエンジンはそれを使用してテーブルのクラスター化インデックスを作成します。一意性を構成するフィールドの1つがタイムスタンプである場合に有利になる範囲スキャンでは、クラスター化インデックスが非常に高速です。テーブルに含めることができるクラスター化インデックスは1つだけです。 MySQLでは、クラスター化インデックスを作成するDBエンジンの優先順位は次のとおりです。
失敗すると、タイムスタンプ、experiment_id、bucket_labelにインデックスを配置しようとします。繰り返しますが、これはクワイエット/ダウンタイムで行うのが最善であり、それを行うために利用可能な物理リソースがあることを確認してください。
別のポイントでは、タイムスタンプなどの予約語であるフィールド名を使用する場合は十分に注意してください。追跡が非常に難しいアプリケーションでスローされる、いくつかの奇妙な例外が発生する可能性があります。
sHOW INDEX FROM event_impressionによると、event_impressionにはPRIMARYキーがありません。カーディナリティー番号を見ると、e_i_timestampなど、列の名前が予約されていないWordに変更された後、e_i_timestamp、user_idをテーブルの複合主キーとして使用できます。 PRIMARY KEYを計画した結果、通常はINNODBのテーブルサイズが小さくなり、40M行に対してより効率的なテーブルになります。