我有以下在大型数据库上运行的查询。
select TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime))
from users
where categoryType='1'
and TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) < 1000
如果您注意到查询和 where 子句中使用了 TIME_TO_SEC。
我尝试了别名,但是由于无法使用别名,所以不知道什么是更好的解决方案。
最佳答案
我发现只有一种优化方法来查询您的问题。当您根据 WHERE 子句中的字段计算值时,MySQL 必须计算每一行。所以每次都是全表扫描,会占用很多时间,而且性能不太好。
使用计算出的时间差和索引创建一个新字段。您不必计算它,您可以使用VIRTUAL PERSISTENT字段,当您插入或更改字段时它会自动计算它
我制作了相同的示例来阐明我的想法:
首先创建一个新表:
CREATE TABLE `users` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`walkStartTime` TIMESTAMP NULL DEFAULT NULL,
`walkEndTime` TIMESTAMP NULL DEFAULT NULL,
`categoryType` INT(11) DEFAULT NULL,
`diffp` INT(11) AS (TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime))) PERSISTENT,
PRIMARY KEY (`id`),
KEY `diffs` (`diffp`)
) ENGINE=INNODB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
插入一些内容:
INSERT INTO `users` (`id`, `walkStartTime`, `walkEndTime`, `categoryType`)
VALUES
(1, '2015-09-27 07:00:00', '2015-09-27 07:30:00', 1),
(2, '2015-09-27 07:00:01', '2015-09-27 07:31:00', 1),
(3, '2015-09-27 07:00:02', '2015-09-27 07:32:00', 0),
(4, '2015-09-27 07:00:10', '2015-09-27 07:15:00', 1),
(5, '2015-09-27 07:00:20', '2015-09-27 07:16:10', 1),
(6, '2015-09-27 07:00:30', '2015-09-27 07:17:20', 0),
(7, '2015-09-27 07:01:00', '2015-09-27 07:10:00', 1),
(8, '2015-09-27 07:02:00', '2015-09-27 07:09:33', 1),
(9, '2015-09-27 07:03:00', '2015-09-27 08:12:00', 1);
尝试您的查询并解释它:看到他们读取了所有 9 行
MariaDB [tmp]> select TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime))
-> from users
-> where categoryType='1'
-> and TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime)) < 1000;
+--------------------------------------------------+
| TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime)) |
+--------------------------------------------------+
| 890 |
| 950 |
| 540 |
| 453 |
+--------------------------------------------------+
4 rows in set (0.00 sec)
MariaDB [tmp]> EXPLAIN select TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime))
-> from users
-> where categoryType='1'
-> and TIME_TO_SEC(TIMEDIFF(walkEndTime,walkStartTime)) < 1000;
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 9 | Using where |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
MariaDB [tmp]>
使用新的 VIRTUAL 字段 (diffp) 运行我的优化查询:
MariaDB [tmp]> SELECT diffp
-> FROM users
-> WHERE diffp < 1000;
+-------+
| diffp |
+-------+
| 453 |
| 540 |
| 890 |
| 950 |
+-------+
4 rows in set (0.00 sec)
MariaDB [tmp]> EXPLAIN SELECT diffp
-> FROM users
-> WHERE diffp < 1000;
+------+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | users | range | diffs | diffs | 5 | NULL | 3 | Using where; Using index |
+------+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
MariaDB [tmp]>
所以你可以看到MySQL只读取3行并使用索引。 当您在两个字段(diffp 和 CategoryType)上使用复合索引时,也有可能可以提高速度,并且索引中两个字段的顺序也可以改变速度。
关于mysql - 优化MYSQL查询TIMEDIFF中Select和where子句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32804585/