MAX() 和 GROUP BY,需要整个结果的 COUNT(*)
MAX() and GROUP BY, need COUNT(*) of whole result
我有一个正在执行的 SELECT
查询,它有一个 MAX()
列和一个 GROUP BY
子句,除了这个查询的结果之外,我还需要 return 给客户端,我还需要 return 所有结果的总数。
基本上我的查询是这样的:
SELECT unique_id, col1, col2, MAX(col3) as col3
FROM tbl
GROUP BY col1, col2
它通常也会有一个 WHERE
子句。
unique_id
是table的主键。
当 return 将此数据发送给客户端时,我还指定了 LIMIT
和 OFFSET
子句以限制一次检索的结果数。我的问题是,如果上面的查询没有 LIMIT
和 OFFSET
子句,我还需要显示结果的总数,以便客户端可以 later/incrementally取回其余部分。
我知道我可以轻松地使用 WITH
临时 table 来获得我想要的东西:
WITH temp AS (
SELECT unique_id, col1, col2, MAX(col3) as col3
FROM tbl
GROUP BY col1, col2
)
SELECT count(*) FROM temp
但我担心这样做的效率。 sans-LIMIT
-and-OFFSET
查询可能 return 数万行,所以我认为 WITH
获取总数的方法不是最好的方法。
有没有我没有想到的更有效的方法?或者 WITH
方法是否合适(例如 MySQL 服务器是否足够“智能”以不分配查询的整个结果集来获取计数)?
示例数据
假设这是我的 table:
中的数据
unique_id col1 col2 col3
___________________________
1 5 8 30
2 5 8 33
3 5 9 40
4 6 8 30
5 6 8 31
6 6 8 32
7 6 9 39
8 7 8 33
9 7 8 32
10 8 8 34
所以我的 SELECT
查询会 return 这个(假设客户端指定 LIMIT 4 OFFSET 0
):
SELECT unique_id, col1, col2, max(col3) as col3
FROM tbl
GROUP BY col1, col2
LIMIT 4
OFFSET 0;
unique_id col1 col2 col3
___________________________
2 5 8 33
3 5 9 40
6 6 8 32
7 6 9 39
然后我会使用该查询 没有 LIMIT
和 OFFSET
子句作为子查询和 SELECT COUNT(*)
从它,其中会 return 6
,我会 return 6
和结果给客户。
MySQL 8 引入了对 window functions 的支持,包括 window 聚合函数。 Window 聚合函数允许您 return 聚合结果和非聚合数据。基本上,您可以通过附加 OVER
子句将常规聚合函数转换为 window 聚合函数,但通常您可能需要指定其他选项,这在链接手册。
您也可以在 GROUP BY
查询中使用 window 聚合函数。在这些情况下,window 聚合函数将在分组完成后应用于行集。另请注意,添加 LIMIT
不会影响 window 聚合函数的结果。
考虑到以上所有因素,您可以像这样修改原始查询:
SELECT
unique_id,
col1,
col2,
MAX(col3) as col3,
COUNT(*) OVER () AS TotalRows
FROM
tbl
GROUP BY
col1,
col2
LIMIT
4 OFFSET 0
;
并一次性得到原始明细数据和行数。 OVER
子句没有附加子句,这意味着它适用于整个行集。
正如我所说,window 聚合函数将忽略 LIMIT
子句,如果一个子句附加到查询。因此,上面的 TotalRows
列将反映行数,就好像没有应用限制一样。
我有一个正在执行的 SELECT
查询,它有一个 MAX()
列和一个 GROUP BY
子句,除了这个查询的结果之外,我还需要 return 给客户端,我还需要 return 所有结果的总数。
基本上我的查询是这样的:
SELECT unique_id, col1, col2, MAX(col3) as col3
FROM tbl
GROUP BY col1, col2
它通常也会有一个 WHERE
子句。
unique_id
是table的主键。
当 return 将此数据发送给客户端时,我还指定了 LIMIT
和 OFFSET
子句以限制一次检索的结果数。我的问题是,如果上面的查询没有 LIMIT
和 OFFSET
子句,我还需要显示结果的总数,以便客户端可以 later/incrementally取回其余部分。
我知道我可以轻松地使用 WITH
临时 table 来获得我想要的东西:
WITH temp AS (
SELECT unique_id, col1, col2, MAX(col3) as col3
FROM tbl
GROUP BY col1, col2
)
SELECT count(*) FROM temp
但我担心这样做的效率。 sans-LIMIT
-and-OFFSET
查询可能 return 数万行,所以我认为 WITH
获取总数的方法不是最好的方法。
有没有我没有想到的更有效的方法?或者 WITH
方法是否合适(例如 MySQL 服务器是否足够“智能”以不分配查询的整个结果集来获取计数)?
示例数据
假设这是我的 table:
中的数据unique_id col1 col2 col3
___________________________
1 5 8 30
2 5 8 33
3 5 9 40
4 6 8 30
5 6 8 31
6 6 8 32
7 6 9 39
8 7 8 33
9 7 8 32
10 8 8 34
所以我的 SELECT
查询会 return 这个(假设客户端指定 LIMIT 4 OFFSET 0
):
SELECT unique_id, col1, col2, max(col3) as col3
FROM tbl
GROUP BY col1, col2
LIMIT 4
OFFSET 0;
unique_id col1 col2 col3
___________________________
2 5 8 33
3 5 9 40
6 6 8 32
7 6 9 39
然后我会使用该查询 没有 LIMIT
和 OFFSET
子句作为子查询和 SELECT COUNT(*)
从它,其中会 return 6
,我会 return 6
和结果给客户。
MySQL 8 引入了对 window functions 的支持,包括 window 聚合函数。 Window 聚合函数允许您 return 聚合结果和非聚合数据。基本上,您可以通过附加 OVER
子句将常规聚合函数转换为 window 聚合函数,但通常您可能需要指定其他选项,这在链接手册。
您也可以在 GROUP BY
查询中使用 window 聚合函数。在这些情况下,window 聚合函数将在分组完成后应用于行集。另请注意,添加 LIMIT
不会影响 window 聚合函数的结果。
考虑到以上所有因素,您可以像这样修改原始查询:
SELECT
unique_id,
col1,
col2,
MAX(col3) as col3,
COUNT(*) OVER () AS TotalRows
FROM
tbl
GROUP BY
col1,
col2
LIMIT
4 OFFSET 0
;
并一次性得到原始明细数据和行数。 OVER
子句没有附加子句,这意味着它适用于整个行集。
正如我所说,window 聚合函数将忽略 LIMIT
子句,如果一个子句附加到查询。因此,上面的 TotalRows
列将反映行数,就好像没有应用限制一样。