我有以下查询在大型数据库上运行。
select TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime))
from users
where categoryType='1'
and TIME_TO_SEC(TIMEDIFF(walkStartTime,walkEndTime)) < 1000
如果您注意到查询以及where子句中使用了TIME_TO_SEC。
我尝试了别名,但由于别名不能使用,所以不知道什么是更好的解决方案。
答案 0 :(得分:0)
一种方法是
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,平均差异和最大差异
答案 1 :(得分:0)
我发现只有一种优化方式来查询您的问题。当您从WHERE子句中的字段计算值时,MySQL必须计算每一行。所以每次全表扫描都会花费很多时间而且性能不高。
使用计算出的timediff和索引花费一个新字段。您不必计算它,您可以使用 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个ROWS并使用索引。 当你在两个字段(diffp和CategoryType)上使用复合索引时,也可以更快地加速,并且索引中两个字段的顺序也可以改变速度。