I have a database using the following schema:
CREATE TABLE IF NOT EXISTS `sessions` (
`starttime` datetime NOT NULL,
`ip` varchar(15) NOT NULL default '',
`country_name` varchar(45) default '',
`country_iso_code` varchar(2) default '',
`org` varchar(128) default '',
KEY (`ip`),
KEY (`starttime`),
KEY (`country_name`)
);
(The actual table contains more columns; I have included only the columns I query on.) The engine is InnoDB.
As you can see, there are 3 indices - on ip, starttime, and country_name.
The table is very large - it contains something like 1.5 million rows. I am running various queries on it, trying to extract a month's worth of information (for the month of August, 2018, in the examples below).
A query like this
SELECT
UNIX_TIMESTAMP(starttime) as time_sec,
country_iso_code AS metric,
COUNT(country_iso_code) AS value
FROM
sessions
WHERE
starttime >= FROM_UNIXTIME(1533070800) AND
starttime <= FROM_UNIXTIME(1535749199)
GROUP BY metric;
is rather slow but bearable (tens of seconds), despite that there is no index on country_iso_code.
(Ignore the first thing in the SELECT; I know that it doesn't seem to make sense, but it is required in the tool that uses the result from the query. Similarly, ignore the use of FROM_UNIXTIME() instead of a date string; this part of the query is generated automatically and I have no control over it.)
However, a query like this
SELECT
country_name AS Country,
COUNT(country_name) AS Attacks
FROM
sessions
WHERE
starttime >= FROM_UNIXTIME(1533070800) AND
starttime <= FROM_UNIXTIME(1535749199)
GROUP BY Country;
is unbearably slow - I let it run for about half an hour and gave up without getting any results.
Results from EXPLAIN:
+----+-------------+----------+------------+-------+------------------------------------+--------------+---------+------+----------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+-------+------------------------------------+--------------+---------+------+----------+----------+-------------+
| 1 | SIMPLE | sessions | NULL | index | starttime,starttime_2,country_name | country_name | 138 | NULL | 14771687 | 35.81 | Using where |
+----+-------------+----------+------------+-------+------------------------------------+--------------+---------+------+----------+----------+-------------+
What exactly is the problem? Should I index on something else? Perhaps a composite index on (starttime, country_name)? I've read this guide but perhaps I've misunderstood it?
Here are some other queries that are similarly slow and probably suffering from the same problem:
Query #2:
SELECT
ip AS IP,
COUNT(ip) AS Attacks
FROM
sessions
WHERE
starttime >= FROM_UNIXTIME(1533070800) AND
starttime <= FROM_UNIXTIME(1535749199)
GROUP BY ip;
Results from EXPLAIN:
+----+-------------+----------+------------+-------+--------------------------+------+---------+------+----------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+-------+--------------------------+------+---------+------+----------+----------+-------------+
| 1 | SIMPLE | sessions | NULL | index | starttime,ip,starttime_2 | ip | 47 | NULL | 14771780 | 35.81 | Using where |
+----+-------------+----------+------------+-------+--------------------------+------+---------+------+----------+----------+-------------+
Query #3:
SELECT
org AS Organization,
COUNT(org) AS Attacks
FROM
sessions
WHERE
starttime >= FROM_UNIXTIME(1533070800) AND
starttime <= FROM_UNIXTIME(1535749199)
GROUP BY Organization;
Results from EXPLAIN:
+----+-------------+----------+------------+-------+---------------------------+------+---------+------+----------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+-------+---------------------------+------+---------+------+----------+----------+-------------+
| 1 | SIMPLE | sessions | NULL | index | starttime,starttime_2,org | org | 387 | NULL | 14771800 | 35.81 | Using where |
+----+-------------+----------+------------+-------+---------------------------+------+---------+------+----------+----------+-------------+
Query #4:
SELECT
ip AS IP,
country_name AS Country,
city_name AS City,
org AS Organization,
COUNT(ip) AS Attacks
FROM
sessions
WHERE
starttime >= FROM_UNIXTIME(1533070800) AND
starttime <= FROM_UNIXTIME(1535749199)
GROUP BY ip;
Results from EXPLAIN:
+----+-------------+----------+------------+-------+--------------------------+------+---------+------+----------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+------------+-------+--------------------------+------+---------+------+----------+----------+-------------+
| 1 | SIMPLE | sessions | NULL | index | starttime,ip,starttime_2 | ip | 47 | NULL | 14771914 | 35.81 | Using where |
+----+-------------+----------+------------+-------+--------------------------+------+---------+------+----------+----------+-------------+