[英]Optimize MYSQL query TIMEDIFF in Select and where Clause
I have the following query which runs over a large database. 我在大型数据库上运行以下查询。
select TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime))
from users
where categoryType='1'
and TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) < 1000
If you notice the TIME_TO_SEC is used in the query as well as in the where clause. 如果您注意到在查询以及where子句中使用了TIME_TO_SEC。
I tried for alias but, as alias can't be use so, don't know what could be a better solution for it. 我尝试使用别名,但是由于不能使用别名,因此不知道有什么更好的解决方案。
One way to do this is 一种方法是
SELECT * FROM (
SELECT TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) diff FROM users WHERE categoryType=1
) a
WHERE a.diff < 1000
assuming you have a column named user_id which contains the user's id 假设您有一个名为user_id的列,其中包含用户的ID
SELECT user_id, AVG(diff) as 'avg_diff', MAX(diff) as 'max_diff' FROM (
SELECT user_id, TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) diff FROM users WHERE categoryType=1
) a
WHERE a.diff < 1000
GROUP BY 1
This will return each user's id, average diff and max diff 这将返回每个用户的ID,平均差异和最大差异
i find only one optimized way to query your problem. 我发现只有一种优化的方法可以查询您的问题。 When you calculate a value from your fields in the WHERE clause MySQL must calculate each row. 当从WHERE子句中的字段计算值时,MySQL必须计算每一行。 So it is every time a full table scan and it can use much time and is not very performant. 因此,这是每次全表扫描,它会花费很多时间,并且性能不是很好。
Spend a new field with the calculated timediff and a index. 用计算出的timediff和索引花费一个新字段。 you not must calculated it, you can use a VIRTUAL PERSISTENT field which calculated it automatic when you insert or change a field 您不必进行计算,可以使用“ 虚拟持久性”字段,该字段会在您插入或更改字段时自动进行计算
I have made same Samples to clarify my idea: 我制作了相同的样本来阐明我的想法:
First create a new table: 首先创建一个新表:
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 some stuff: 插入一些东西:
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);
try your query and EXPLAIN it: see that they read all 9 rows 尝试查询并解释它:看到它们读取了所有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]>
run my optimized query with the new VIRTUAL field (diffp): 使用新的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]>
so you can see MySQL only reads 3 ROWS and use the Index. 因此您可以看到MySQL仅读取3 ROWS并使用Index。 It is also possible that can can more speedup when you using a composite index over both fields (diffp and CategoryType) and the order of the both fields in the index can also change the speed. 在两个字段(diffp和CategoryType)上使用复合索引时,还可能会提高速度,并且索引中两个字段的顺序也会改变速度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.