Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Select和where子句中优化MYSQL查询TIMEDIFF_Mysql_Query Optimization_Alias - Fatal编程技术网

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

在Select和where子句中优化MYSQL查询TIMEDIFF,mysql,query-optimization,alias,Mysql,Query Optimization,Alias,我有一个运行在大型数据库上的查询 select TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) from users where categoryType='1' and TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) < 1000 如果您注意到查询中以及where子句中使用了TIME_TO_SEC 我尝试了alias,但由于alias无法使用,所以不知道有什么更好的解决方案。一种方

我有一个运行在大型数据库上的查询

select TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) 
from users 
where categoryType='1' 
and TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) < 1000
如果您注意到查询中以及where子句中使用了TIME_TO_SEC

我尝试了alias,但由于alias无法使用,所以不知道有什么更好的解决方案。

一种方法是

SELECT * FROM (
    SELECT TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) diff FROM users WHERE categoryType=1
) a
WHERE a.diff < 1000
使现代化 假设您有一个名为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

这将返回每个用户的id、平均差异和最大差异。我只找到一种优化的方法来查询您的问题。从WHERE子句中的字段计算值时,MySQL必须计算每一行。因此,它是每次一个完整的表扫描,它可以使用大量的时间,并不是很好的性能

使用一个新字段,其中包含计算的timediff和索引。您不必计算它,您可以使用一个虚拟持久字段,当您插入或更改字段时,该字段会自动计算它

我制作了相同的样品以澄清我的想法:

首先创建一个新表:

插入一些内容:

尝试您的查询并解释它:确保他们读取所有9行

使用新的虚拟字段diffp运行我的优化查询:

因此,您可以看到MySQL只读取3行并使用索引。
在diffp和CategoryType两个字段上使用复合索引时,也可能会加快速度,而且索引中这两个字段的顺序也会改变速度。

你能建议一些关于获取MAX和AVG time的建议吗,比如AVGTIME_TO_SECTIMEDIFF和MAXTIME_TO_SECTIMEDIFF?@andyPaul,平均值通常是用户明智的或其他的。你能分享一些样本数据和你期望的结果吗?很好的解释。但是有一个问题,像diff这样的键会有什么帮助呢?当你在WHERE子句中调用一个函数,并将字段作为参数时,MySQL必须为每一行调用这个函数,看看是否要用于这个查询的行以及MySQL是否不能将结果存储在查询缓存中,因为函数的结果每次都可能不同。diff只是一个虚拟字段,MySQL自动存储两个时间戳之间的差异(以秒为单位)。如果你也在这个字段上加了一个键,MySQL可以直接在WHERE子句中搜索它上面的值。
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);
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]>
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]>