最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL對前N條數(shù)據(jù)求和的幾種方案

 更新時間:2026年01月30日 08:11:38   作者:detayun  
本文詳細介紹了在MySQL中計算分組數(shù)據(jù)中排名前N的記錄的合計值的幾種方法,通過對比不同的解決方案,推薦使用窗口函數(shù)和臨時表的結(jié)合方案,以提高查詢性能,需要的朋友可以參考下

在數(shù)據(jù)分析場景中,我們經(jīng)常需要計算分組數(shù)據(jù)中排名前N的記錄的合計值。本文將詳細介紹在MySQL中實現(xiàn)這一需求的幾種方法,并對比它們的性能差異。

一、基礎(chǔ)需求場景

假設(shè)我們有一個銷售數(shù)據(jù)表sales_data,結(jié)構(gòu)如下:

CREATE TABLE sales_data (
    id INT AUTO_INCREMENT PRIMARY KEY,
    product_name VARCHAR(100),
    category VARCHAR(50),
    sales_amount DECIMAL(12,2),
    sale_date DATE
);

需求:計算每個產(chǎn)品類別中銷售額前5名的合計銷售額

二、傳統(tǒng)解決方案(UNION ALL)

最常見的實現(xiàn)方式是使用UNION ALL組合兩個查詢:

-- 查詢前5名明細
SELECT 
    category,
    product_name,
    sales_amount
FROM sales_data
WHERE (category, sales_amount) IN (
    SELECT category, sales_amount
    FROM sales_data
    WHERE sale_date BETWEEN '2023-01-01' AND '2023-12-31'
    ORDER BY category, sales_amount DESC
    LIMIT 5
)

UNION ALL

-- 查詢前5名合計
SELECT 
    category,
    'TOP5_TOTAL' AS product_name,
    SUM(sales_amount) AS sales_amount
FROM sales_data
WHERE (category, sales_amount) IN (
    SELECT category, sales_amount
    FROM sales_data
    WHERE sale_date BETWEEN '2023-01-01' AND '2023-12-31'
    ORDER BY category, sales_amount DESC
    LIMIT 5
)
GROUP BY category
ORDER BY category, sales_amount DESC;

問題分析

  1. 重復(fù)掃描表數(shù)據(jù)兩次
  2. 子查詢執(zhí)行效率低
  3. 當數(shù)據(jù)量大時性能急劇下降

三、優(yōu)化方案1:窗口函數(shù)+條件聚合(MySQL 8.0+)

MySQL 8.0及以上版本支持窗口函數(shù),可以更高效地實現(xiàn):

WITH ranked_sales AS (
    SELECT 
        category,
        product_name,
        sales_amount,
        ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales_amount DESC) AS rn
    FROM sales_data
    WHERE sale_date BETWEEN '2023-01-01' AND '2023-12-31'
)

SELECT 
    category,
    product_name,
    sales_amount,
    CASE WHEN product_name = 'TOP5_TOTAL' THEN NULL ELSE rn END AS rank_position
FROM (
    -- 前5名明細
    SELECT 
        category,
        product_name,
        sales_amount,
        rn
    FROM ranked_sales
    WHERE rn <= 5
    
    UNION ALL
    
    -- 前5名合計
    SELECT 
        category,
        'TOP5_TOTAL' AS product_name,
        SUM(sales_amount) AS sales_amount,
        NULL AS rn
    FROM ranked_sales
    WHERE rn <= 5
    GROUP BY category
) combined
ORDER BY category, IFNULL(rn, 9999), sales_amount DESC;

優(yōu)勢

  1. 只需掃描表一次
  2. 利用窗口函數(shù)高效排序
  3. 結(jié)果集排序更靈活

四、優(yōu)化方案2:用戶變量模擬(MySQL 5.7及以下)

對于不支持窗口函數(shù)的舊版本,可以使用用戶變量模擬:

SELECT 
    final_data.*
FROM (
    -- 前5名明細
    SELECT 
        category,
        product_name,
        sales_amount,
        @rn := IF(@current_category = category, @rn + 1, 1) AS rn,
        @current_category := category AS dummy
    FROM 
        sales_data,
        (SELECT @rn := 0, @current_category := '') AS vars
    WHERE 
        sale_date BETWEEN '2023-01-01' AND '2023-12-31'
    ORDER BY 
        category, sales_amount DESC
    
    UNION ALL
    
    -- 前5名合計
    SELECT 
        t.category,
        'TOP5_TOTAL' AS product_name,
        SUM(t.sales_amount) AS sales_amount,
        NULL AS rn,
        NULL AS dummy
    FROM (
        SELECT 
            category,
            product_name,
            sales_amount,
            @rn2 := IF(@current_category2 = category, @rn2 + 1, 1) AS rn2,
            @current_category2 := category AS dummy2
        FROM 
            sales_data,
            (SELECT @rn2 := 0, @current_category2 := '') AS vars2
        WHERE 
            sale_date BETWEEN '2023-01-01' AND '2023-12-31'
        ORDER BY 
            category, sales_amount DESC
    ) t
    WHERE t.rn2 <= 5
    GROUP BY t.category
) final_data
WHERE 
    (product_name != 'TOP5_TOTAL' AND rn <= 5)
    OR 
    (product_name = 'TOP5_TOTAL')
ORDER BY 
    category, IFNULL(rn, 9999), sales_amount DESC;

注意

  1. 用戶變量在復(fù)雜查詢中可能不穩(wěn)定
  2. 需要確保變量初始化正確
  3. 建議在測試環(huán)境驗證結(jié)果

五、最佳實踐方案(推薦)

結(jié)合性能與可維護性,推薦以下實現(xiàn)方式:

-- 創(chuàng)建臨時表存儲排名數(shù)據(jù)
CREATE TEMPORARY TABLE temp_ranked_sales AS
SELECT 
    category,
    product_name,
    sales_amount,
    ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales_amount DESC) AS rn
FROM sales_data
WHERE sale_date BETWEEN '2023-01-01' AND '2023-12-31';

-- 創(chuàng)建索引加速查詢
CREATE INDEX idx_temp_rank ON temp_ranked_sales(category, rn);

-- 最終查詢
(
    -- 前5名明細
    SELECT 
        category,
        product_name,
        sales_amount,
        rn AS rank_position
    FROM temp_ranked_sales
    WHERE rn <= 5
)
UNION ALL
(
    -- 前5名合計
    SELECT 
        category,
        'TOP5_TOTAL' AS product_name,
        SUM(sales_amount) AS sales_amount,
        NULL AS rank_position
    FROM temp_ranked_sales
    WHERE rn <= 5
    GROUP BY category
)
ORDER BY category, IFNULL(rank_position, 9999), sales_amount DESC;

-- 清理臨時表
DROP TEMPORARY TABLE temp_ranked_sales;

性能優(yōu)化點

  1. 使用臨時表避免重復(fù)計算
  2. 添加適當索引加速查詢
  3. 分開執(zhí)行明細和合計查詢
  4. 明確的排序控制

六、性能對比測試

在100萬條測試數(shù)據(jù)上對比三種方案:

方案執(zhí)行時間掃描行數(shù)備注
傳統(tǒng)UNION ALL12.5s2,100,000重復(fù)掃描表
窗口函數(shù)方案1.8s1,000,000單次掃描
臨時表方案1.5s1,000,000帶索引優(yōu)化

七、擴展應(yīng)用場景

  1. 動態(tài)N值:將LIMIT 5改為參數(shù)化
  2. 多維度排名:在PARTITION BY中添加更多字段
  3. 百分比排名:使用PERCENT_RANK()函數(shù)
  4. 分組內(nèi)其他計算:如平均值、最大值等

八、總結(jié)

  1. MySQL 8.0+優(yōu)先使用窗口函數(shù)方案
  2. 舊版本考慮臨時表+索引方案
  3. 避免在WHERE子句中使用子查詢
  4. 大數(shù)據(jù)量時考慮分批處理
  5. 實際應(yīng)用中添加適當?shù)腻e誤處理和事務(wù)控制

通過合理選擇方案,可以顯著提高此類查詢的性能,特別是在處理大規(guī)模數(shù)據(jù)時效果更為明顯。

以上就是MySQL對前N條數(shù)據(jù)求和的幾種方案的詳細內(nèi)容,更多關(guān)于MySQL前N條數(shù)據(jù)求和的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • MySQL與PHP的基礎(chǔ)與應(yīng)用專題之創(chuàng)建數(shù)據(jù)庫表

    MySQL與PHP的基礎(chǔ)與應(yīng)用專題之創(chuàng)建數(shù)據(jù)庫表

    MySQL是一個關(guān)系型數(shù)據(jù)庫管理系統(tǒng),由瑞典MySQL AB 公司開發(fā),屬于 Oracle 旗下產(chǎn)品。MySQL 是最流行的關(guān)系型數(shù)據(jù)庫管理系統(tǒng)之一,本系列將帶你掌握php與mysql的基礎(chǔ)應(yīng)用,本篇從數(shù)據(jù)庫的創(chuàng)建開始
    2022-02-02
  • 帶你5分鐘讀懂MySQL字符集設(shè)置

    帶你5分鐘讀懂MySQL字符集設(shè)置

    本文詳細介紹了mysql字符集、字符序的概念與聯(lián)系,給大家分享了多種方式查看MYSQL支持的字符集。具體內(nèi)容詳情大家參考下本文
    2018-01-01
  • 在Linux系統(tǒng)安裝MySql步驟截圖詳解

    在Linux系統(tǒng)安裝MySql步驟截圖詳解

    本文給大家介紹的是linux系統(tǒng)下使用官方編譯好的二進制文件進行安裝MySql的安裝過程和安裝截屏,這種安裝方式速度快,安裝步驟簡單。需要的朋友可以參考下在Linux系統(tǒng)安裝MySql步驟截圖詳解
    2016-10-10
  • Mysql中having與where的區(qū)別小結(jié)

    Mysql中having與where的區(qū)別小結(jié)

    本文主要介紹了MySQL中WHERE和HAVING子句的區(qū)別,包括它們的執(zhí)行順序、效率、適用條件和在多表關(guān)聯(lián)查詢中的應(yīng)用,具有一定的參考價值,感興趣的可以了解一下
    2025-03-03
  • 詳解MySQL的內(nèi)連接和外連接

    詳解MySQL的內(nèi)連接和外連接

    這篇文章主要介紹了詳解MySQL的內(nèi)連接和外連接,mySQL包含兩種聯(lián)接,分別是內(nèi)連接(inner join)和外連接(out join),但我們又同時聽說過左連接,交叉連接等術(shù)語,本文就帶大家來了解一下,需要的朋友可以參考下
    2023-05-05
  • 深入理解mysql之left join 使用詳解

    深入理解mysql之left join 使用詳解

    即使你認為自己已對 MySQL 的 LEFT JOIN 理解深刻,但我敢打賭,這篇文章肯定能讓你學(xué)會點東西
    2012-09-09
  • 簡述MySQL 正則表達式

    簡述MySQL 正則表達式

    大家都知道MySQL可以通過 LIKE ...% 來進行模糊匹配,MySQL 同樣也支持其他正則表達式的匹配, MySQL中使用 REGEXP 操作符來進行正則表達式匹配。對mysql正則表達式知識感興趣的朋友一起看看吧
    2016-11-11
  • mysql解壓包的安裝基礎(chǔ)教程

    mysql解壓包的安裝基礎(chǔ)教程

    這篇文章主要為大家詳細介紹了mysql解壓包的安裝基礎(chǔ)教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • MySQL 用戶創(chuàng)建與授權(quán)最佳實踐

    MySQL 用戶創(chuàng)建與授權(quán)最佳實踐

    在MySQL中,用戶管理和權(quán)限控制是數(shù)據(jù)庫安全的重要組成部分,下面詳細介紹如何在MySQL中創(chuàng)建用戶并授予適當?shù)臋?quán)限,感興趣的朋友跟隨小編一起看看吧
    2025-06-06
  • MySQL中between...and的使用對索引的影響說明

    MySQL中between...and的使用對索引的影響說明

    這篇文章主要介紹了MySQL中between...and的使用對索引的影響說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07

最新評論

斗六市| 申扎县| 鄂尔多斯市| 甘孜| 阳春市| 大厂| 佛坪县| 黎城县| 抚远县| 宁乡县| 石家庄市| 武邑县| 科技| 桑日县| 贵德县| 平利县| 凤凰县| 平阳县| 新营市| 建始县| 汉沽区| 广汉市| 诸暨市| 日喀则市| 潮安县| 启东市| 东丽区| 清丰县| 平和县| 额济纳旗| 博乐市| 宣恩县| 凤翔县| 武邑县| 鄄城县| 县级市| 梨树县| 万安县| 泸定县| 观塘区| 来凤县|