benhsu
benhsu

Reputation: 5536

How can I speed up a MySQL query with WHERE clauses on two columns?

I am trying to speed up a query on a large table with WHERE clauses on two columns, as far as I can, MySQL is only using the ALERT_ID column.

Is there a way to rewrite this query using both indices?

SHOW_INDEX and EXPLAIN output is below.

show index from alert_hit;

+-----------+------------+-------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name          | Seq_in_index | Column_name       | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+-------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| alert_hit |          0 | PRIMARY           |            1 | id                | A         |    15181402 |     NULL | NULL   |      | BTREE      |         |               |
| alert_hit |          1 | alert_id          |            1 | alert_id          | A         |          20 |     NULL | NULL   | YES  | BTREE      |         |               |
| alert_hit |          1 | timestamp         |            1 | timestamp         | A         |      446511 |     NULL | NULL   | YES  | BTREE      |         |               |
| alert_hit |          1 | data_source_id    |            1 | data_source_id    | A         |          20 |     NULL | NULL   | YES  | BTREE      |         |               |
| alert_hit |          1 | filter_syndicated |            1 | filter_syndicated | A         |          20 |     NULL | NULL   | YES  | BTREE      |         |               |
| alert_hit |          1 | unique_id         |            1 | unique_id         | A         |     5060467 |     NULL | NULL   | YES  | BTREE      |         |               |
| alert_hit |          1 | date_created      |            1 | date_created      | A         |      281137 |     NULL | NULL   |      | BTREE      |         |               |
| alert_hit |          1 | language          |            1 | language          | A         |          20 |     NULL | NULL   | YES  | BTREE      |         |               |
| alert_hit |          1 | region            |            1 | region            | A         |       42406 |     NULL | NULL   | YES  | BTREE      |         |               |
| alert_hit |          1 | market_rank       |            1 | market_rank       | A         |          20 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------+------------+-------------------+--------------+-------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

explain select count(id) as history FROM alert_hit force index(alert_id, timestamp) where alert_id in (9045,9046,9047,9048,9049,9050,9051,9052,9330,9332)  AND timestamp between DATE_SUB( NOW(), INTERVAL 1*2 day) and DATE_SUB( NOW(), INTERVAL 1 day);
+----+-------------+-----------+-------+--------------------+----------+---------+------+-------+-------------+
| id | select_type | table     | type  | possible_keys      | key      | key_len | ref  | rows  | Extra       |
+----+-------------+-----------+-------+--------------------+----------+---------+------+-------+-------------+
|  1 | SIMPLE      | alert_hit | range | alert_id,timestamp | alert_id | 5       | NULL | 99578 | Using where |
+----+-------------+-----------+-------+--------------------+----------+---------+------+-------+-------------+

Upvotes: 2

Views: 1352

Answers (1)

Vatev
Vatev

Reputation: 7590

You need to have one index on both fields

ALTER TABLE alert_hit ADD INDEX `IDX-alert_id-timestamp` (`alert_id`, `timestamp`);

Also MySQL will use the multi column index up to the first field for which there is a range condition in the WHERE clause, so in this case order matters and timestamp should be last in the index.

As suggested by @spencer7593 selecting COUNT(1) instead of count(id) might also be better.

Upvotes: 5

Related Questions