I'm searching for an effective index for my table layout. Or maybe for hints to change my table layout.
I have a table with start
, end
and actual
values (timestamps, simplified with low numbers in the examples below). actual
can increase until it reaches end
.
CREATE TABLE `t1` (
`id` int(10) unsigned NOT NULL DEFAULT '0',
`start` int(10) unsigned NOT NULL DEFAULT '0',
`actual` int(10) unsigned NOT NULL DEFAULT '0',
`end` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `actual` (`actual`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `t1`
(`id`, `start`, `actual`, `end`)
VALUES
(1, 1, 0, 5),
(2, 1, 6, 6),
(3, 2, 8, 9),
(4, 2, 5, 9);
In my SELECT
result I want all rows from the table with actual
values smaller the current timestamp (to simplify the example lets say the current timestamp is 7). Additionally I want only these rows with actual
values smaller than end
. This second condition makes the problem.
SELECT `id`
FROM `t1`
WHERE `actual` < `end`
AND `actual` < 7;
+----+
| id |
+----+
| 1 |
| 4 |
+----+
2 rows in set (0.00 sec)
The index will be used for actual < 7
, but I suppose not for actual < end
. Because the comparision of actual < end
will be done for all ancient rows the query become slower with every new (old) row in the table.
end < 7
does not solve the problem, because I want outdated rows with actual < end
in the result.
I could add a new computed column to the table named remaining
with a value of end
- actual
and use the WHERE
condition WHERE remaining > 0 AND actual < 7
(and sure change the index or create a new one). But I have a problem with this, it feels like a bad table layout. If someone updates end
and forget to also update the computed remainig
I have a broken row.
Explain result:
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | t1 | ALL | actual | NULL | NULL | NULL | 4 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
Change the key definition to:
KEY `actual_end` (`actual`,`end`)
Explain result:
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
| 1 | SIMPLE | t1 | range | actual_end | actual_end | 4 | NULL | 3 | Using where; Using index |
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
This last Explain prove that the index is used for actual < 7
and not for actual < end
. With 1 billion ancient rows the last condition will examine 1 billion rows. I want to optimize this problem.