简体   繁体   English

在Select和where子句中优化MYSQL查询TIMEDIFF

[英]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

Update 更新资料

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM