簡體   English   中英

MySQL,DISTINCT在SUM操作中

[英]MySQL, DISTINCT in SUM operation

目前,我正在嘗試根據用戶性別來計算應用程序中唯一身份用戶訪問的次數。 這是計算所有訪問次數(非唯一)的示例查詢

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)

使用子查詢進行了嘗試,並計算出不同的效果,但速度慢了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)

有什么建議嗎?

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);

我不知道是否會更快。

每個查詢(用戶和訪問)都有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;

查詢結果

此查詢將為您提供在特定日期按性別划分的唯一用戶數。

這種類型的查詢可能會比較慢,尤其是當您在表中有大量條目時,例如當基於日期和時間值選擇行時,mysql必須執行全表掃描。

優化數據庫結構可能會為您帶來比以這種方式查詢數據庫要多得多的性能。

有兩個建議是按日期范圍對表格進行分區。 這樣做可以大大減少查詢的執行,因為這意味着與其進行全表掃描,mysql可以簡單地忽略查詢日期范圍以外的任何分區。 表格越大,您將看到的好處越多,但是我期望的速度可能是2倍到10倍。

如果要將“性別”列替換為“ male ,“ female和“ unknown三列,則可以用條件較少的單個查詢替換包含慢速COUNT(DISTINCT ...語句)的3個查詢,也可以將用戶ID添加到組中語句,因為您可以為分組指定多個列,從而消除了計算非重復數的需要。

最后,您可以添加一個數據庫觸發器,並且如果持續時間超過30並且是一天中的首次訪問,則可以添加一個額外的列(在記錄訪問時將其設置為1),或者為訪問創建一個新的日歷表並獲取觸發器在數據庫中寫入每個日志后,將值增加為一天中的唯一訪問量。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM