MySQL 分組函數(shù)全面詳解與最佳實(shí)踐(最新整理)
MySQL 分組函數(shù)全面詳解與最佳實(shí)踐
MySQL 分組函數(shù)(聚合函數(shù))的核心知識(shí)、注意事項(xiàng)和高級(jí)應(yīng)用技巧:
?? 分組函數(shù)核心列表
函數(shù) | 描述 | 示例 |
---|---|---|
COUNT() | 計(jì)算行數(shù) | COUNT(*) |
SUM() | 計(jì)算數(shù)值總和 | SUM(salary) |
AVG() | 計(jì)算平均值 | AVG(score) |
MAX() | 獲取最大值 | MAX(price) |
MIN() | 獲取最小值 | MIN(price) |
GROUP_CONCAT() | 連接分組字符串 | GROUP_CONCAT(name) |
STDDEV() | 計(jì)算標(biāo)準(zhǔn)差 | STDDEV(price) |
VAR_POP() | 計(jì)算總體方差 | VAR_POP(sales) |
?? 分組函數(shù)十大注意事項(xiàng)
1. NULL 值處理
SELECT COUNT(*), -- 所有行數(shù)(包含NULL) COUNT(bonus), -- 非NULL行數(shù) AVG(COALESCE(bonus, 0)) -- NULL轉(zhuǎn)為0計(jì)算 FROM employees;
2. 分組字段選擇
-- 錯(cuò)誤:非分組字段出現(xiàn)在SELECT SELECT department, name, AVG(salary) FROM employees; -- 報(bào)錯(cuò)或未定義行為 -- 正確:所有非聚合字段必須出現(xiàn)在GROUP BY SELECT department, name, AVG(salary) FROM employees GROUP BY department, name;
3. WHERE vs HAVING
-- WHERE:分組前過(guò)濾行 SELECT department, AVG(salary) FROM employees WHERE hire_date > '2020-01-01' -- 先過(guò)濾 GROUP BY department; -- HAVING:分組后過(guò)濾組 SELECT department, AVG(salary) avg_sal FROM employees GROUP BY department HAVING avg_sal > 5000; -- 后過(guò)濾
4. 性能優(yōu)化策略
-- 低效:全表掃描 SELECT department, AVG(salary) FROM employees GROUP BY department; -- 高效:添加索引 ALTER TABLE employees ADD INDEX idx_dept (department);
5. 隱式排序問(wèn)題
-- 結(jié)果順序不保證 SELECT department, COUNT(*) FROM employees GROUP BY department; -- 顯式排序 SELECT department, COUNT(*) AS emp_count FROM employees GROUP BY department ORDER BY emp_count DESC;
6. 分組函數(shù)嵌套限制
-- 允許:?jiǎn)螌臃纸M函數(shù) SELECT AVG(MAX(salary)) -- ? 錯(cuò)誤嵌套 -- 正確:使用子查詢 SELECT AVG(max_sal) FROM ( SELECT department, MAX(salary) AS max_sal FROM employees GROUP BY department ) dept_max;
7. DISTINCT 用法
-- 統(tǒng)計(jì)不重復(fù)值 SELECT COUNT(DISTINCT department), -- 不同部門數(shù)量 COUNT(DISTINCT CASE WHEN salary > 5000 THEN 1 END) -- 高薪人數(shù) FROM employees;
8. 空分組處理
-- 使用 COALESCE 處理空分組 SELECT COALESCE(department, '未分配') AS dept, COUNT(*) FROM employees GROUP BY department;
9. 多列分組順序
-- 分組順序影響結(jié)果 SELECT YEAR(hire_date) AS hire_year, department, COUNT(*) FROM employees GROUP BY hire_year, department; -- 先按年再按部門
10. GROUP_CONCAT 限制
-- 默認(rèn)截?cái)嚅L(zhǎng)度1024字符 SET SESSION group_concat_max_len = 10000; SELECT department, GROUP_CONCAT(name ORDER BY salary DESC SEPARATOR '|') FROM employees GROUP BY department;
?? 高級(jí)分組技巧
1. 多級(jí)分組分析
SELECT YEAR(order_date) AS order_year, QUARTER(order_date) AS quarter, product_category, SUM(amount) AS total_sales, COUNT(DISTINCT customer_id) AS customers FROM orders GROUP BY order_year, quarter, product_category WITH ROLLUP; -- 添加小計(jì)和總計(jì)行
2. 分組百分比計(jì)算
SELECT department, COUNT(*) AS emp_count, ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER (), 2) AS pct FROM employees GROUP BY department;
3. 分組排名
SELECT department, name, salary, RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank FROM employees;
4. 分組比較分析
SELECT department, AVG(salary) AS avg_salary, AVG(salary) - (SELECT AVG(salary) FROM employees) AS diff_from_avg FROM employees GROUP BY department;
5. 時(shí)間序列分組
SELECT DATE_FORMAT(order_date, '%Y-%m') AS month, SUM(amount) AS monthly_sales, LAG(SUM(amount)) OVER (ORDER BY DATE_FORMAT(order_date, '%Y-%m')) AS prev_month FROM orders GROUP BY month;
?? 性能優(yōu)化指南
1. 索引策略
-- 復(fù)合索引優(yōu)化分組 ALTER TABLE orders ADD INDEX idx_category_date (product_category, order_date); -- 覆蓋索引 EXPLAIN SELECT product_category, COUNT(*) FROM orders GROUP BY product_category; -- 使用索引
2. 臨時(shí)表優(yōu)化
-- 增大臨時(shí)表內(nèi)存 SET tmp_table_size = 256*1024*1024; -- 256MB SET max_heap_table_size = 256*1024*1024; -- 監(jiān)控臨時(shí)表使用 SHOW STATUS LIKE 'Created_tmp%';
3. 分區(qū)表優(yōu)化
-- 按日期分區(qū) CREATE TABLE sales ( sale_id INT, sale_date DATE, amount DECIMAL(10,2) ) PARTITION BY RANGE (YEAR(sale_date)) ( PARTITION p2020 VALUES LESS THAN (2021), PARTITION p2021 VALUES LESS THAN (2022), PARTITION p2022 VALUES LESS THAN (2023) ); -- 分區(qū)分組查詢 SELECT YEAR(sale_date), SUM(amount) FROM sales GROUP BY YEAR(sale_date); -- 僅掃描相關(guān)分區(qū)
4. 物化視圖(MySQL 8.0+)
-- 創(chuàng)建分組結(jié)果緩存 CREATE TABLE sales_summary AS SELECT product_id, YEAR(order_date) AS year, SUM(amount) AS total FROM orders GROUP BY product_id, year; -- 定期刷新 REPLACE INTO sales_summary SELECT product_id, YEAR(order_date), SUM(amount) FROM orders WHERE order_date > (SELECT MAX(order_date) FROM sales_summary) GROUP BY product_id, YEAR(order_date);
?? 最佳實(shí)踐總結(jié)
1. 分組設(shè)計(jì)原則
-- 明確分組粒度 SELECT DATE(order_date) AS day, -- 按天 HOUR(order_time) AS hour, -- 按小時(shí) COUNT(*) FROM orders GROUP BY day, hour;
2. 安全處理大數(shù)據(jù)集
-- 分頁(yè)處理大結(jié)果集 SELECT department, AVG(salary) FROM employees GROUP BY department LIMIT 10 OFFSET 20; -- 第三頁(yè)
3. 結(jié)果驗(yàn)證技巧
-- 驗(yàn)證分組總數(shù) SELECT COUNT(DISTINCT department) FROM employees; -- 應(yīng)與分組行數(shù)一致 -- 交叉驗(yàn)證 SELECT (SELECT COUNT(*) FROM employees) AS total, SUM(emp_count) AS group_total FROM ( SELECT department, COUNT(*) AS emp_count FROM employees GROUP BY department ) dept_groups;
4. 執(zhí)行計(jì)劃分析
-- 檢查分組性能 EXPLAIN SELECT department, AVG(salary) FROM employees GROUP BY department; -- 關(guān)注以下指標(biāo): -- 1. Using temporary (是否使用臨時(shí)表) -- 2. Using filesort (是否文件排序) -- 3. key (使用的索引)
5. 避免常見(jiàn)陷阱
-- 陷阱1:錯(cuò)誤處理NULL SELECT department, AVG(bonus) -- 忽略NULL FROM employees; -- 陷阱2:混淆WHERE和HAVING SELECT department, AVG(salary) FROM employees WHERE AVG(salary) > 5000; -- 錯(cuò)誤!WHERE不能使用聚合函數(shù) -- 陷阱3:未排序的分頁(yè) SELECT department, COUNT(*) FROM employees GROUP BY department LIMIT 10; -- 結(jié)果隨機(jī)
?? 綜合應(yīng)用案例
銷售分析報(bào)告
SELECT c.country, p.category, YEAR(o.order_date) AS order_year, COUNT(DISTINCT o.customer_id) AS customers, COUNT(*) AS orders, SUM(o.amount) AS revenue, AVG(o.amount) AS avg_order_value, GROUP_CONCAT(DISTINCT p.product_name ORDER BY p.product_name SEPARATOR ', ') AS products FROM orders o JOIN products p ON o.product_id = p.id JOIN customers c ON o.customer_id = c.id WHERE o.order_date BETWEEN '2023-01-01' AND '2023-12-31' GROUP BY c.country, p.category, order_year WITH ROLLUP HAVING revenue > 10000 ORDER BY country, category, order_year DESC;
到此這篇關(guān)于MySQL 分組函數(shù)全面詳解與最佳實(shí)踐的文章就介紹到這了,更多相關(guān)mysql 分組函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何通過(guò)sql查找所有父節(jié)點(diǎn)和所有子節(jié)點(diǎn)(以mysql為例)
這篇文章主要給大家介紹了關(guān)于如何通過(guò)sql查找所有父節(jié)點(diǎn)和所有子節(jié)點(diǎn),本文以mysql為例,項(xiàng)目中遇到一個(gè)需求,要求查處菜單節(jié)點(diǎn)的所有節(jié)點(diǎn),這里給大家總結(jié)下,需要的朋友可以參考下2023-08-08在windows上安裝不同(兩個(gè))版本的Mysql數(shù)據(jù)庫(kù)的教程詳解
這篇文章主要介紹了在windows上安裝不同(兩個(gè))版本的Mysql數(shù)據(jù)庫(kù) ,需要的朋友可以參考下2019-04-04MySQL索引優(yōu)化指南之如何科學(xué)為數(shù)據(jù)表添加索引
在數(shù)據(jù)庫(kù)優(yōu)化中,索引(Index)是最常用的性能優(yōu)化手段之一,正確的索引可以大幅提升查詢速度,本文小編就來(lái)和大家講講如何為數(shù)據(jù)表科學(xué)添加索引吧2025-05-05Mysql數(shù)據(jù)庫(kù)緩沖池詳解(Buffer pool)
InnoDB存儲(chǔ)引擎通過(guò)BufferPool緩存數(shù)據(jù)頁(yè)和索引頁(yè),減少磁盤I/O,提升查詢性能,BufferPool通過(guò)預(yù)讀和checkpoint機(jī)制優(yōu)化I/O操作和數(shù)據(jù)持久化2024-12-12