我在 PHP 中使用带有 PDO 的 MySQL,并且我有一个 SQL 查询,它按预期工作。但是,我关心性能并且想知道我是否可以改进我的查询。我也在问,因为我想获得更多的SQL背景知识。
假设我有两个表,它们有几个相等的字段(以及一些附加信息,每个表中都不同):
table `blog_comments`: id, userid (int) | timestamp (int) | content (varchar) | other
table `projects_comments`: id, userid (int) | timestamp (int) | content (varchar) | other
该字段id
是主键,在两个表中userid + timestamp
都有一个索引,时间戳就是长度为 10(整数)的 unixtime。
作为一种简单的垃圾邮件防护,我会阻止用户提交新评论(无论是博客、项目还是其他任何内容),直到他上次发表评论后 60 秒。为此,我从所有评论表中获取该用户的最新时间戳。
这是我的工作查询:
SELECT MAX(`last_timestamp`) AS `last_timestamp`
FROM
(
SELECT `userid`, max(`timestamp`) AS `last_timestamp`
FROM `blog_comments`
GROUP BY `userid`
UNION ALL
SELECT `userid`, max(`timestamp`) as `last_timestamp`
FROM `projects_comments`
GROUP BY `userid`
) AS `subquery`
WHERE `userid` = 1
LIMIT 0, 1;
如您所见,我在子查询中使用了GROUP BY,在主查询中我只是过滤了用户 ID(在本例中为:1)。优点:我只需要将用户标识作为参数传递一次。
现在,我对 SQL 究竟是如何工作的很感兴趣。我认为它会是这样的:SQL 首先执行子查询,按用户 ID对所有现有行进行分组并将整个集合返回给主查询,然后应用 where 子句来查找所需的用户 ID。这对我来说似乎是一个很大的性能泄漏。
所以我想稍微改变一下查询:
SELECT max(`last_timestamp`) AS `last_timestamp`
FROM
(
SELECT max(`timestamp`) AS `last_timestamp`
FROM `blog_comments`
WHERE `userid` = 1
UNION ALL
SELECT max(`timestamp`) as `last_timestamp`
FROM `projects_comments`
WHERE `userid` = 1
) AS `subquery`
LIMIT 0, 1
现在我必须传递用户 ID 两次,仍然会为给定的用户 ID 查找整组行。我不确定这是否真的可以提高性能。
我还没有任何大数据量来真正测试它,也许我稍后会做一些测试场景。我真的很想知道这些表中何时会有很多数据集是否会有差异?
将不胜感激任何想法,信息和提示,在此先感谢。
编辑:
MySQL对第一个查询的解释:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 4 Using where
2 DERIVED blog_comments range NULL userid 8 NULL 10 Using index for group-by
3 UNION projects_comments index NULL userid 12 NULL 6 Using index
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL
MySQL 对第二个查询的解释:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2
2 DERIVED NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
3 UNION NULL NULL NULL NULL NULL NULL NULL Select tables optimized away
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL