MySQL?count()聚合函數(shù)詳解
深入剖析一下 MySQL 中的 COUNT() 函數(shù)。它是 SQL 中最常用的聚合函數(shù)之一,用于計(jì)算表中符合特定條件的行數(shù)。
核心功能
COUNT() 函數(shù)的核心功能是計(jì)數(shù)。它可以用來:
統(tǒng)計(jì)表中所有行的總數(shù)。
統(tǒng)計(jì)表中特定列的非 NULL 值的數(shù)量。
結(jié)合
WHERE子句,統(tǒng)計(jì)滿足特定條件的行的數(shù)量。結(jié)合
GROUP BY子句,統(tǒng)計(jì)每個(gè)分組中的行數(shù)。
語法形式
COUNT() 函數(shù)主要有三種語法形式,它們在行為和性能上有所不同:
COUNT(*)
功能: 統(tǒng)計(jì)查詢結(jié)果集中的總行數(shù)。
計(jì)數(shù)方式: 它計(jì)算所有行,不管該行中的列是否包含 NULL 值。即使整行所有列都是 NULL,
COUNT(*)也會將其計(jì)入。性能: 在大多數(shù)現(xiàn)代 MySQL 版本(尤其是 InnoDB 存儲引擎)中,
COUNT(*)通常經(jīng)過高度優(yōu)化。MySQL 知道COUNT(*)只需要行數(shù),而不需要檢查任何具體的列值。這是獲取表總行數(shù)或分組行數(shù)的推薦方式。示例:
-- 統(tǒng)計(jì) `users` 表中的總用戶數(shù) SELECT COUNT(*) FROM users; -- 統(tǒng)計(jì)每個(gè)部門 (`dept_id`) 的員工數(shù)量 SELECT dept_id, COUNT(*) AS employee_count FROM employees GROUP BY dept_id;
COUNT(expression)功能: 統(tǒng)計(jì)表達(dá)式
expression計(jì)算結(jié)果為非 NULL 值的行數(shù)。計(jì)數(shù)方式: 對每一行計(jì)算給定的表達(dá)式 (
expression)。如果表達(dá)式的結(jié)果是 非 NULL,則計(jì)數(shù)加 1;如果結(jié)果是 NULL,則不計(jì)入。expression可以是:一個(gè)列名 (
COUNT(column_name)):統(tǒng)計(jì)該列中非 NULL 值的數(shù)量。這是最常見的使用方式。一個(gè)常量 (
COUNT(1),COUNT('abc')):因?yàn)槌A坑肋h(yuǎn)是非 NULL 的,所以COUNT(1)或COUNT('任何常量')的行為幾乎總是等同于COUNT(*),統(tǒng)計(jì)總行數(shù)。現(xiàn)代 MySQL 優(yōu)化器通常會將COUNT(1)轉(zhuǎn)換為COUNT(*)來執(zhí)行。一個(gè)表達(dá)式 (
COUNT(UPPER(name)),COUNT(price * quantity)):先計(jì)算表達(dá)式,然后判斷結(jié)果是否為 NULL。
性能: 如果
expression是一個(gè)列名,MySQL 需要檢查該列的值是否為 NULL。如果該列沒有索引,對于大表來說,這可能比COUNT(*)稍慢一些(因?yàn)?nbsp;COUNT(*)可以利用存儲引擎的內(nèi)部優(yōu)化)。如果expression是常量,性能通常與COUNT(*)相當(dāng)。示例:
-- 統(tǒng)計(jì) `users` 表中設(shè)置了郵箱 (`email` 列非 NULL) 的用戶數(shù) SELECT COUNT(email) FROM users; -- 統(tǒng)計(jì) `orders` 表中總金額 (`total_amount`) 大于 100 的訂單數(shù)量 (假設(shè) total_amount 可為 NULL) SELECT COUNT(total_amount > 100) FROM orders; -- 注意:`total_amount > 100` 的結(jié)果是布爾值 (TRUE, FALSE, 或 NULL)。在 MySQL 中,TRUE=1, FALSE=0, NULL=NULL。所以 COUNT 只會計(jì)入結(jié)果為 TRUE (1) 的非 NULL 行。 -- 更常見的寫法是結(jié)合 WHERE: SELECT COUNT(*) FROM orders WHERE total_amount > 100; -- 統(tǒng)計(jì) `products` 表中 `name` 字段非 NULL 的產(chǎn)品數(shù)量 (等同于 COUNT(name)) SELECT COUNT(*) FROM products WHERE name IS NOT NULL; -- 另一種寫法
COUNT(DISTINCT expression)功能: 統(tǒng)計(jì)表達(dá)式
expression計(jì)算結(jié)果中不同(唯一、去重后)的非 NULL 值的數(shù)量。計(jì)數(shù)方式: 首先計(jì)算所有行中
expression的值,然后去除結(jié)果集中的 NULL 值,最后對剩下的非 NULL 值進(jìn)行去重,統(tǒng)計(jì)去重后的數(shù)量。性能: 這是性能開銷最大的一種形式,因?yàn)樗婕暗綄λ蟹?NULL 值進(jìn)行排序或使用哈希表來去重。對于大表,尤其是在沒有合適索引的情況下,可能會比較慢。
示例:
-- 統(tǒng)計(jì) `users` 表中來自不同城市 (`city`) 的數(shù)量 (忽略 city 為 NULL 的行) SELECT COUNT(DISTINCT city) FROM users; -- 統(tǒng)計(jì) `orders` 表中每個(gè)客戶 (`customer_id`) 下了多少種不同商品 (`product_id`) 的訂單 SELECT customer_id, COUNT(DISTINCT product_id) AS unique_products_ordered FROM orders GROUP BY customer_id;
重要特性與行為
COUNT()與 NULL:COUNT(*):不關(guān)心 NULL,統(tǒng)計(jì)所有行。COUNT(expression):只統(tǒng)計(jì)expression計(jì)算結(jié)果為非 NULL 的行。COUNT(DISTINCT expression):只統(tǒng)計(jì)expression計(jì)算結(jié)果為非 NULL 的值,并且對這些非 NULL 值進(jìn)行去重計(jì)數(shù)。
聚合函數(shù):
COUNT()是一個(gè)聚合函數(shù)。它通常作用于一組行(可能是整個(gè)表,或者GROUP BY定義的每個(gè)組),并返回一個(gè)單一的匯總值。與
WHERE結(jié)合:WHERE子句在聚合發(fā)生之前過濾行。COUNT()只會計(jì)入通過WHERE條件過濾后的行。SELECT COUNT(*) FROM orders WHERE order_date >= '2024-01-01'; -- 統(tǒng)計(jì)2024年及之后的訂單數(shù)
與
GROUP BY結(jié)合:GROUP BY將數(shù)據(jù)分成多個(gè)組,COUNT()會為每個(gè)組單獨(dú)計(jì)算行數(shù)或非 NULL 值的數(shù)量。SELECT status, COUNT(*) AS order_count FROM orders GROUP BY status; -- 統(tǒng)計(jì)每種訂單狀態(tài)的數(shù)量
與
HAVING結(jié)合:HAVING子句在聚合發(fā)生之后過濾分組結(jié)果。它基于聚合結(jié)果(如COUNT(*))來篩選哪些分組應(yīng)該出現(xiàn)在最終結(jié)果中。SELECT country, COUNT(*) AS user_count FROM users GROUP BY country HAVING user_count > 100; -- 只顯示用戶數(shù)超過100的國家
COUNT()返回類型:COUNT()函數(shù)返回一個(gè)BIGINT類型的值(64位整數(shù))。即使結(jié)果很小,返回類型也是BIGINT。沒有匹配行: 如果查詢沒有匹配任何行(例如,
WHERE條件太嚴(yán)格),COUNT()將返回 0。COUNT(DISTINCT ...)在沒有非 NULL 值時(shí)也返回 0。性能考慮(MyISAM vs InnoDB):
MyISAM: 對于
COUNT(*)且沒有WHERE條件的查詢(如SELECT COUNT(*) FROM myisam_table;),MyISAM 引擎會極其快速地返回結(jié)果,因?yàn)樗苯釉诒淼脑獢?shù)據(jù)中存儲了精確的總行數(shù)。InnoDB: InnoDB 引擎不存儲精確的總行數(shù)在元數(shù)據(jù)中。它需要掃描表(或最小的可用索引)來計(jì)算
COUNT(*)(即使沒有WHERE子句)。這是因?yàn)?MVCC(多版本并發(fā)控制)機(jī)制使得同時(shí)存在的事務(wù)可能看到表中不同版本的行數(shù)。因此,對于非常大的 InnoDB 表,SELECT COUNT(*) FROM huge_innodb_table;可能會比較慢。估算行數(shù)可以考慮查詢information_schema.TABLES表的TABLE_ROWS列(注意這是估算值,不精確?。?,或者使用計(jì)數(shù)器表、緩存等技術(shù)。
如何選擇使用哪種形式?
需要總行數(shù)? ?? 優(yōu)先使用
COUNT(*)。它是語義最清晰(計(jì)算行數(shù)),且在 MySQL 中通常性能最佳。需要統(tǒng)計(jì)特定列的非 NULL 值數(shù)量? ?? 使用
COUNT(column_name)。需要統(tǒng)計(jì)滿足特定條件的行數(shù)? ?? 結(jié)合
WHERE子句使用COUNT(*)(推薦) 或COUNT(1)。SELECT COUNT(*) FROM table WHERE condition;
需要統(tǒng)計(jì)某一列中不同值的數(shù)量(去重計(jì)數(shù))? ?? 使用
COUNT(DISTINCT column_name)。需要統(tǒng)計(jì)滿足某個(gè)表達(dá)式條件的行數(shù)? ?? 使用
COUNT(expression),或者更常見的,使用COUNT(*)+WHERE子句。SELECT COUNT(IF(score > 90, 1, NULL)) FROM students;-- 統(tǒng)計(jì)分?jǐn)?shù)大于90的學(xué)生數(shù)等價(jià)于
SELECT COUNT(*) FROM students WHERE score > 90;(通常更推薦后者)
總結(jié)
COUNT() 函數(shù)是 MySQL 中用于計(jì)數(shù)的核心聚合函數(shù)。理解 COUNT(*)、COUNT(expression) 和 COUNT(DISTINCT expression) 之間的區(qū)別至關(guān)重要:
COUNT(*):統(tǒng)計(jì)所有行(推薦用于計(jì)數(shù)總行數(shù)或分組行數(shù))。COUNT(expression):統(tǒng)計(jì)expression結(jié)果非 NULL 的行數(shù)(用于統(tǒng)計(jì)特定列的非 NULL 值)。COUNT(DISTINCT expression):統(tǒng)計(jì)expression結(jié)果中不同(唯一)的非 NULL 值的數(shù)量(用于去重計(jì)數(shù))。
根據(jù)你的具體需求(是統(tǒng)計(jì)行數(shù)、特定列的非 NULL 值數(shù)、還是唯一值數(shù))選擇正確的形式,并結(jié)合 WHERE、GROUP BY、HAVING 子句來精確控制計(jì)數(shù)范圍
到此這篇關(guān)于MySQL count()聚合函數(shù)詳解的文章就介紹到這了,更多相關(guān)mysql count() 聚合函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL數(shù)據(jù)庫中varchar類型的數(shù)字比較大小的方法
varchar類型的數(shù)據(jù)是不能直接比較大小的,那么MySQL數(shù)據(jù)庫中varchar類型如何進(jìn)行數(shù)字比較大小的,本文就詳細(xì)的介紹一下2021-11-11
mysql 直接拷貝data 目錄下文件還原數(shù)據(jù)的實(shí)現(xiàn)
這篇文章主要介紹了mysql 直接拷貝data 目錄下文件還原數(shù)據(jù)的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
解決MySQL啟動報(bào)錯(cuò):ERROR 2003 (HY000): Can''t connect to MySQL serv
這篇文章主要介紹了解決MySQL啟動報(bào)錯(cuò):ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061),本文解釋了如何解決該問題,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
mysql如何修改表結(jié)構(gòu)(alter table),多列/多字段
這篇文章主要介紹了mysql如何修改表結(jié)構(gòu)(alter table),多列/多字段問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
mysql根據(jù)逗號將一行數(shù)據(jù)拆分成多行數(shù)據(jù)
本文主要介紹了mysql根據(jù)逗號將一行數(shù)據(jù)拆分成多行數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
MySQL事務(wù)的基礎(chǔ)學(xué)習(xí)以及心得分享
本篇內(nèi)容是關(guān)于MySQL事務(wù)的基礎(chǔ)知識學(xué)習(xí)內(nèi)容,并把學(xué)習(xí)中網(wǎng)友的心得做了總結(jié),分享給大家,一起學(xué)習(xí)參考下吧。2017-12-12

