mysql,在求和运算中是不同的

zbsbpyhn  于 2021-06-20  发布在  Mysql
关注(0)|答案(3)|浏览(268)

目前,我正在尝试根据用户性别计算应用程序中的唯一用户访问次数。下面是计算所有访问量的示例查询(不是唯一的)

SELECT
    DATE(v.visited_at) AS visit_date,
    SUM(IF(u.gender = 'M', 1, 0)) AS male_visit,
    SUM(IF(u.gender = 'F', 1, 0)) AS female_visit,
    SUM(IF(u.gender = '' OR u.gender IS NULL, 1, 0)) AS unknown_visit
FROM 
    visits v
    INNER JOIN users u ON v.user_id = u.id
WHERE
    DATE(v.visited_at) >= DATE_SUB(SYSDATE(), INTERVAL 30 DAY)
    AND v.duration > 30
GROUP BY
    DATE(v.visited_at)

尝试使用子查询和count distinct,但速度慢了4倍。

SELECT
    DATE(visited_at) as visit_date,
    (SELECT COUNT(DISTINCT u.id) FROM visits v JOIN users u ON v.user_id = u.id WHERE u.gender = 'M' AND DATE(v.visited_at) = visit_date AND v.duration > 30) AS male_visit,
    (SELECT COUNT(DISTINCT u.id) FROM visits v JOIN users u ON v.user_id = u.id WHERE u.gender = 'F' AND DATE(v.visited_at) = visit_date AND v.duration > 30) AS female_visit,
    (SELECT COUNT(DISTINCT u.id) FROM visits v JOIN users u ON v.user_id = u.id WHERE u.gender = '' OR u.gender IS NULL AND DATE(v.visited_at) = visit_date AND v.duration > 30) AS unknown_visit
FROM 
    visits v
WHERE
    DATE(visited_at) >= DATE_SUB(SYSDATE(), INTERVAL 30 DAY)
GROUP BY
    DATE(visited_at)

有什么建议吗?

ogq8wdun

ogq8wdun1#

每个查询(用户和访问)有2个表,其中包含示例数据。

查询

SELECT
DATE(v.visited_date) AS visit_date,
u.gender,
COUNT(DISTINCT v.user_id) AS total_count
FROM
visits v
INNER JOIN users u ON v.user_id = u.id
WHERE
DATE(v.visited_date) >= DATE_SUB(SYSDATE(), INTERVAL 30 DAY)
AND v.duration >= 30
GROUP BY u.gender,DATE(v.visited_date)
ORDER BY DATE(v.visited_date) ASC;


此查询将为您提供特定日期的按性别划分的用户的唯一计数。

zc0qhyus

zc0qhyus2#

COUNT(DISTINCT) 总是比 COUNT() . 您可以尝试:

SELECT DATE(v.visited_at) AS visit_date,
       COUNT(DISTINCT CASE WHEN u.gender = 'M' THEN u.id END) AS male_visit,
       COUNT(DISTINCT CASE WHEN u.gender = 'F' THEN u.id END) AS female_visit,
       COUNT(DISTINCT CASE WHEN u.gender = '' OR u.gender IS NULL THEN u.id END) AS unknown_visit
FROM visits v INNER JOIN
     users u
     ON v.user_id = u.id
WHERE DATE(v.visited_at) >= DATE_SUB(SYSDATE(), INTERVAL 30 DAY) AND
      v.duration > 30
GROUP BY DATE(v.visited_at);

不过,我不知道会不会快很多。

pftdvrlh

pftdvrlh3#

这种类型的查询可能很慢,特别是当表中有大量条目时,因为在基于日期和时间值选择行时,mysql必须执行完整的表扫描。
优化您的数据库结构很可能会为您带来性能上的好处,远远超过您这样查询它所能获得的任何好处。
一些建议是按日期范围划分表。这样做可以极大地减少查询执行,因为这意味着mysql可以忽略查询日期范围之外的任何分区,而不是完全的表扫描。table越大,你会看到更多的好处,但可能会比我预期的快2倍到10倍。
如果你要用3栏代替性别栏 male , female 以及 unknown 您将替换3个包含慢计数的查询(不同的。。。语句,您还可以将用户id添加到GROUPBY语句中,以消除对distinct进行计数的需要,因为您可以为分组指定多个列。
最后,您可以添加一个数据库触发器,如果访问持续时间超过30并且是他们一天中的第一次访问,则可以在记录访问时设置一个额外的列为1,或者为访问创建一个新的日历表,并让触发器在数据库写入每个日志时增加该表中的值,这相当于当天的唯一访问。

相关问题