Suppose I have the following table in MySQL:
CREATE TABLE `events` (
`pv_name` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
`time_stamp` bigint(20) unsigned NOT NULL,
`event_type` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
`value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
`value_type` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`value_count` bigint(20) DEFAULT NULL,
`alarm_status` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`alarm_severity` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`pv_name`,`time_stamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED;
Is there any way to improve the following query with indexes or otherwise?
SELECT DISTINCT events.pv_name
FROM events
WHERE events.time_stamp > t0_in AND events.time_stamp < t1_in
AND (events.value IS NULL OR events.alarm_severity = 'INVALID');
t0_in
and t1_in
are parameters passed to the stored procedure the query is defined in.
Running the query with EXPLAIN gives:
+----+-------------+--------+-------+---------------+---------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+------+----------+-------------+
| 1 | SIMPLE | events | index | PRIMARY | PRIMARY | 250 | NULL | 12724016 | Using where |
+----+-------------+--------+-------+---------------+---------+---------+------+----------+-------------+
Running the query on the database returns 102620 rows in 1 min 50.93 sec.
UPDATE
Suppose for simplicity that the table is the following:
CREATE TABLE `events` (
`pv_name` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
`time_stamp` bigint(20) unsigned NOT NULL,
`value_valid` tinyint(1) NOT NULL,
PRIMARY KEY (`pv_name`,`time_stamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED;
Is it possible to add appropriate indexes so that the following or an equivalent query uses loose index scan optimization?
SELECT DISTINCT events.pv_name
FROM events
WHERE events.time_stamp > t0_in AND events.time_stamp < t1_in
AND events.value_valid = 0);
UPDATE
If I add an index on time_stamp
I get:
mysql> EXPLAIN SELECT DISTINCT events.pv_name FROM events WHERE events.time_stamp > 0 AND events.time_stamp < 11426224880000000000 AND (events.value IS NULL OR events.alarm_severity = 'INVALID');
+----+-------------+--------+-------+--------------------+---------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+--------------------+---------+---------+------+----------+-------------+
| 1 | SIMPLE | events | index | PRIMARY,time_stamp | PRIMARY | 250 | NULL | 13261211 | Using where |
+----+-------------+--------+-------+--------------------+---------+---------+------+----------+-------------+
Running this query on the database returns 11511 rows in 30.44 sec.
mysql> EXPLAIN SELECT DISTINCT events.pv_name FROM events FORCE INDEX (time_stamp) WHERE events.time_stamp > 0 AND events.time_stamp < 11426224880000000000 AND (events.value IS NULL OR events.alarm_severity = 'INVALID');
+----+-------------+--------+-------+--------------------+------------+---------+------+---------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+--------------------+------------+---------+------+---------+-----------------------------------------------------+
| 1 | SIMPLE | events | range | PRIMARY,time_stamp | time_stamp | 8 | NULL | 6630605 | Using index condition; Using where; Using temporary |
+----+-------------+--------+-------+--------------------+------------+---------+------+---------+-----------------------------------------------------+
Running this query on the database returns 11511 rows in 2 min 20.41 sec.
UPDATE
From the suggestions I have changed the table to:
CREATE TABLE `events` (
`pv_name` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
`time_stamp` bigint(20) unsigned NOT NULL,
`event_type` enum('add','init','update','disconnect','remove') COLLATE utf8mb4_unicode_ci NOT NULL,
`value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
`value_type` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`value_count` bigint(20) DEFAULT NULL,
`alarm_status` enum('NO_ALARM','READ','WRITE','HIHI','HIGH','LOLO','LOW','STATE','COS','COMM','TIMEOUT','HWLIMIT','CALC','SCAN','LINK','SOFT','BAD_SUB','UDF','DISABLE','SIMM','READ_ACCESS','WRITE_ACCESS') COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`alarm_severity` enum('NO_ALARM','MINOR','MAJOR','INVALID') COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`pv_name`,`time_stamp`),
KEY `event_type` (`event_type`,`time_stamp`),
KEY `alarm_severity` (`alarm_severity`,`time_stamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED;
and the query to:
SELECT DISTINCT events.pv_name
FROM events
WHERE events.time_stamp > 0 AND events.time_stamp < 1426224880000000000
AND alarm_severity = 'INVALID'
UNION
SELECT DISTINCT events.pv_name
FROM events
WHERE events.time_stamp > 0 AND events.time_stamp < 1426224880000000000
AND event_type = 'add'
UNION
SELECT DISTINCT events.pv_name
FROM events
WHERE events.time_stamp > 0 AND events.time_stamp < 1426224880000000000
AND event_type = 'disconnect'
UNION
SELECT DISTINCT events.pv_name
FROM events
WHERE events.time_stamp > 0 AND events.time_stamp < 1426224880000000000
AND event_type = 'remove';
Running explain on the query gives:
+----+--------------+----------------+-------+-----------------------------------+----------------+---------+------+--------+-------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+----------------+-------+-----------------------------------+----------------+---------+------+--------+-------------------------------------------+
| 1 | PRIMARY | events | range | PRIMARY,event_type,alarm_severity | alarm_severity | 10 | NULL | 101670 | Using where; Using index; Using temporary |
| 2 | UNION | events | range | PRIMARY,event_type,alarm_severity | event_type | 9 | NULL | 994652 | Using where; Using index; Using temporary |
| 3 | UNION | events | range | PRIMARY,event_type,alarm_severity | event_type | 9 | NULL | 73660 | Using where; Using index; Using temporary |
| 4 | UNION | events | range | PRIMARY,event_type,alarm_severity | event_type | 9 | NULL | 136348 | Using where; Using index; Using temporary |
| NULL | UNION RESULT | <union1,2,3,4> | ALL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+----------------+-------+-----------------------------------+----------------+---------+------+--------+-------------------------------------------+
Running the query on the database returns 112620 rows in 1 min 2.45 sec.