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

MySQL中count(*)深度解析與性能優(yōu)化實(shí)踐案例

 更新時間:2025年12月30日 09:26:01   作者:·云揚(yáng)·  
這篇文章給大家介紹MySQL中count(*)深度解析與性能優(yōu)化實(shí)踐,本文將結(jié)合實(shí)際測試案例,從原理到實(shí)踐,帶你徹底搞懂count(*),并分享3種高效優(yōu)化count()性能的方案,感興趣的朋友跟隨小編一起看看吧

在日常MySQL開發(fā)中,count()函數(shù)是統(tǒng)計數(shù)據(jù)行數(shù)的常用工具,但很多開發(fā)者對count(*)、count(字段)count(1)的區(qū)別一知半解,也常困惑于不同存儲引擎下count(*)的性能差異。本文將結(jié)合實(shí)際測試案例,從原理到實(shí)踐,帶你徹底搞懂count(*),并分享3種高效優(yōu)化count()性能的方案。

一、測試環(huán)境搭建

為了讓所有結(jié)論有數(shù)據(jù)支撐,我們先搭建統(tǒng)一的測試環(huán)境——創(chuàng)建3張不同配置的表(InnoDB帶索引、MyISAM、InnoDB無二級索引),并插入測試數(shù)據(jù)。

1.1 建表語句與存儲過程

-- 切換數(shù)據(jù)庫(需提前創(chuàng)建martin庫:create database martin;)
use martin;
-- 1. 創(chuàng)建InnoDB引擎表t1(含主鍵+二級索引)
drop table if exists t1; 
CREATE TABLE `t1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `a` int DEFAULT NULL,  -- 允許為null,用于測試count(字段)
  `b` int NOT NULL,
  `c` int DEFAULT NULL,
  `d` int DEFAULT NULL,
  PRIMARY KEY (`id`),    -- 聚簇索引
  KEY `idx_a` (`a`),     -- 二級索引
  KEY `idx_b` (`b`)      -- 二級索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 2. 創(chuàng)建批量插入10000條數(shù)據(jù)的存儲過程
drop procedure if exists insert_t1; 
delimiter ;;  -- 臨時修改語句結(jié)束符,避免與存儲過程中的;沖突
create procedure insert_t1() 
begin
declare i int; 
set i=1; 
while(i<=10000)do 
insert into t1(a,b,c,d) values(i,i,i,i);  -- 初始數(shù)據(jù)a無null
set i=i+1; 
end while;
end;;
delimiter ;  -- 恢復(fù)語句結(jié)束符
-- 3. 執(zhí)行存儲過程+補(bǔ)充1條a為null的數(shù)據(jù)
call insert_t1(); 
insert into t1(a,b,c,d) values (null,10001,10001,10001),(10002,10002,10002,10002);
-- 此時t1共10002行數(shù)據(jù),其中1行a為null
-- 4. 創(chuàng)建MyISAM引擎表t2(結(jié)構(gòu)與t1一致,用于對比引擎差異)
drop table if exists t2;
create table t2 like t1; 
alter table t2 engine = MyISAM;  -- 修改引擎
insert into t2 select * from t1;  -- 同步t1數(shù)據(jù)
-- 5. 創(chuàng)建無二級索引的InnoDB表t3(用于測試索引對count(*)的影響)
drop table if exists t3; 
CREATE TABLE `t3` (
  `id` int NOT NULL AUTO_INCREMENT,
  `a` int DEFAULT NULL,
  `b` int NOT NULL,
  `c` int DEFAULT NULL,
  `d` int DEFAULT NULL,
  PRIMARY KEY (`id`)  -- 僅聚簇索引
) ENGINE=InnoDB CHARSET=utf8mb4;
insert into t3 select * from t1;

二、重新認(rèn)識count(*):4個核心疑問解答

2.1 count(a)與count(*)的區(qū)別:是否統(tǒng)計null?

很多人誤以為count(字段)count(*)功能一致,實(shí)則關(guān)鍵差異在是否統(tǒng)計字段為null的行

  • count(a):僅統(tǒng)計a字段不為null的行(若字段有null值,會過濾掉);
  • count(*):統(tǒng)計表中所有行(無論字段是否為null,包括全null的行)。

測試驗(yàn)證(基于t1表,10002行,1行a為null):

-- 結(jié)果為10001(排除a為null的1行)
select count(a) from t1;
-- 結(jié)果為10002(統(tǒng)計所有行)
select count(*) from t1;

2.2 MyISAM與InnoDB:count(*)性能天差地別?

兩種主流引擎對count(*)的處理邏輯完全不同,導(dǎo)致性能差異顯著:

  • MyISAM:會將表的總行數(shù)存儲在磁盤(僅針對無where子句、無其他列檢索的場景),查詢時直接讀取該值,速度極快;
  • InnoDB:需臨時掃描表/索引計算行數(shù)(因InnoDB支持事務(wù),行數(shù)據(jù)可能被鎖定或版本不同,無法緩存固定行數(shù)),速度較慢。

執(zhí)行計劃對比

-- 1. MyISAM表t2的count(*):Extra為Select tables optimized away,核心含義是:MySQL 通過優(yōu)化邏輯,直接從索引中獲取了所需的全部數(shù)據(jù),完全無需訪問實(shí)際的表,因此 “跳過了表的訪問步驟”
explain select count(*) from t2;
-- 2. InnoDB表t1的count(*):type為index,表示 “全索引掃描”,而非 “全表掃描”,Extra為Using index,表示查詢所需的所有信息都能從索引中直接獲取,完全不需要回表讀取行數(shù)據(jù)
explain select count(*) from t1;

從執(zhí)行計劃可見,MyISAM直接復(fù)用預(yù)存的行數(shù),而InnoDB需掃描索引計算。

2.3 MySQL 5.7.18+:count(*)為何優(yōu)先選二級索引?

在MySQL 5.7.18之前,InnoDB的count(*)默認(rèn)掃描聚簇索引(主鍵索引);而5.7.18之后,優(yōu)化器會優(yōu)先選擇最小的二級索引,原因是:

  • 聚簇索引的葉子節(jié)點(diǎn)存儲整行數(shù)據(jù),體積較大;
  • 二級索引的葉子節(jié)點(diǎn)僅存儲主鍵值,體積遠(yuǎn)小于聚簇索引,掃描成本更低。

若表無二級索引(如t3表),則仍會掃描聚簇索引。

2.4 count(1)比count(*)快?謠言!

很多開發(fā)者認(rèn)為count(1)性能優(yōu)于count(*),實(shí)則兩者結(jié)果一致、性能無差異

  • count(1):將“1”視為恒真表達(dá)式,統(tǒng)計所有行(與count(*)邏輯一致);
  • count(*):MySQL對其有專門優(yōu)化,不會展開為所有字段,而是直接統(tǒng)計行數(shù)。

執(zhí)行計劃驗(yàn)證

-- 兩條語句的執(zhí)行計劃完全一致(均掃描二級索引,rows=10002)
explain select count(1) from t1;
explain select count(*) from t1;

結(jié)論:無需糾結(jié)count(1)count(*),優(yōu)先用count(*)更符合語義。

三、3種方法加快count():從“慢統(tǒng)計”到“快查詢”

當(dāng)表數(shù)據(jù)量達(dá)百萬/千萬級時,InnoDB的count(*)會明顯變慢,以下3種方案可根據(jù)場景選擇:

3.1 場景1:僅需“大概數(shù)據(jù)量”→ show table status

若業(yè)務(wù)無需精確行數(shù)(如后臺數(shù)據(jù)概覽),可使用show table status,它直接讀取MySQL的表元數(shù)據(jù),無需掃描表:

-- 結(jié)果中Rows字段即為表的大概行數(shù)(t1表約10002行)
show table status like 't1';

優(yōu)缺點(diǎn):速度極快,但數(shù)據(jù)可能有誤差(誤差通常在10%以內(nèi))。

3.2 場景2:需高性能+可接受少量延遲→ Redis計數(shù)器

利用Redis的原子操作(INCR/DECR)維護(hù)表行數(shù),查詢時直接讀Redis,避免掃描MySQL表:

步驟1:初始化計數(shù)器

-- 1. 先查詢MySQL表的初始行數(shù)
select count(*) from t1;  -- 結(jié)果10002
-- 2. 將初始值寫入Redis(key為t1_count,值為10002)
set t1_count 10002;

步驟2:增刪數(shù)據(jù)時同步更新計數(shù)器

-- 插入數(shù)據(jù)時,Redis計數(shù)器+1
insert into t1(a,b,c,d) values (10003,10003,10003,10003);
INCR t1_count;  -- Redis命令
-- 刪除數(shù)據(jù)時,Redis計數(shù)器-1
delete from t1 where id=10003;
DECR t1_count;  -- Redis命令

步驟3:查詢行數(shù)時讀Redis

-- 直接獲取Redis中的值,耗時微秒級
get t1_count;

優(yōu)缺點(diǎn):性能極高,但存在“Redis與MySQL數(shù)據(jù)不一致”風(fēng)險(如插入MySQL成功但Redis更新失?。?,適合對一致性要求不嚴(yán)格的場景。

3.3 場景3:需強(qiáng)一致性→ 計數(shù)表(InnoDB)

用一張InnoDB表專門存儲行數(shù),通過事務(wù)保證“數(shù)據(jù)操作”與“計數(shù)更新”的原子性,徹底解決一致性問題:

步驟1:創(chuàng)建計數(shù)表

-- 創(chuàng)建count_t1表,僅存儲t1的行數(shù)
create table count_t1 (
  table_name varchar(50) not null primary key,  -- 表名(可擴(kuò)展到多表)
  count int not null default 0  -- 行數(shù)
);
-- 初始化t1的計數(shù)
insert into count_t1(table_name, count) values ('t1', (select count(*) from t1));

步驟2:事務(wù)中同步增刪與計數(shù)

-- 插入數(shù)據(jù)時,在同一事務(wù)中更新計數(shù)
begin;  -- 開啟事務(wù)
insert into t1(a,b,c,d) values (10003,10003,10003,10003);
update count_t1 set count=count+1 where table_name='t1';
commit;  -- 提交事務(wù)(要么都成功,要么都失?。?
-- 刪除數(shù)據(jù)時同理
begin;
delete from t1 where id=10003;
update count_t1 set count=count-1 where table_name='t1';
commit;

步驟3:查詢行數(shù)時讀計數(shù)表

-- 直接查詢計數(shù)表,僅掃描1行,速度極快
select count from count_t1 where table_name='t1';

優(yōu)缺點(diǎn):強(qiáng)一致性、性能好,但需額外維護(hù)計數(shù)表,適合對數(shù)據(jù)一致性要求高的核心業(yè)務(wù)(如訂單數(shù)統(tǒng)計)。

四、總結(jié):count(*)使用與優(yōu)化指南

  1. 基礎(chǔ)選擇:統(tǒng)計所有行用count(*),統(tǒng)計非null字段用count(字段),無需用count(1);
  2. 引擎差異:MyISAM適合靜態(tài)表(行數(shù)不變),InnoDB需通過索引優(yōu)化count(*)
  3. 優(yōu)化方案
    • 概覽數(shù)據(jù):show table status;
    • 高性能低一致性:Redis計數(shù)器;
    • 強(qiáng)一致性:InnoDB計數(shù)表。

掌握以上知識,可避免在MySQL計數(shù)場景中踩坑,讓統(tǒng)計邏輯既高效又可靠。

到此這篇關(guān)于MySQL中count(*)深度解析與性能優(yōu)化實(shí)踐案例的文章就介紹到這了,更多相關(guān)mysql count(*)性能優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于MySQL文件排序用法解讀

    基于MySQL文件排序用法解讀

    這篇文章主要介紹了MySQL文件排序用法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-07-07
  • Navicat連接mysql報錯1251錯誤的解決方法

    Navicat連接mysql報錯1251錯誤的解決方法

    這篇文章主要為大家詳細(xì)介紹了Navicat連接mysql報錯1251錯誤的解決方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • MySQL范圍查詢優(yōu)化的場景實(shí)例詳解

    MySQL范圍查詢優(yōu)化的場景實(shí)例詳解

    范圍訪問方法使用單一索引去檢索表中的數(shù)據(jù)包含一個或者多個索引值的行記錄,下面這篇文章主要給大家介紹了關(guān)于MySQL范圍查詢優(yōu)化的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • Centos7下MySQL安裝教程

    Centos7下MySQL安裝教程

    這篇文章主要為大家詳細(xì)介紹了Centos7下MySQL安裝教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • MySQL常見數(shù)值函數(shù)整理

    MySQL常見數(shù)值函數(shù)整理

    MySQL中另外一類很重要的函數(shù)就是數(shù)值函數(shù),這些函數(shù)能處理很多數(shù)值方面的運(yùn)算,下面這篇文章主要給大家介紹了關(guān)于MySQL常見數(shù)值函數(shù)整理的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • MySQL 自增 ID 超過 int 最大值的問題解決

    MySQL 自增 ID 超過 int 最大值的問題解決

    本文主要介紹了MySQL 自增 ID 超過 int 最大值的問題解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-06-06
  • mysql實(shí)現(xiàn)游標(biāo)分頁的方法詳解

    mysql實(shí)現(xiàn)游標(biāo)分頁的方法詳解

    這篇文章主要為大家詳細(xì)介紹了mysql實(shí)現(xiàn)游標(biāo)分頁的相關(guān)方法,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-10-10
  • Mysql常用sql語句匯總

    Mysql常用sql語句匯總

    這篇文章主要介紹了Mysql常用sql語句匯總的相關(guān)資料,需要的朋友可以參考下
    2017-09-09
  • mysql存儲過程之返回多個值的方法示例

    mysql存儲過程之返回多個值的方法示例

    這篇文章主要介紹了mysql存儲過程之返回多個值的方法,結(jié)合實(shí)例形式分析了mysql存儲過程返回多個值的實(shí)現(xiàn)方法與PHP調(diào)用技巧,需要的朋友可以參考下
    2019-12-12
  • Window10下安裝 mysql5.7圖文教程(解壓版)

    Window10下安裝 mysql5.7圖文教程(解壓版)

    這篇文章主要介紹了Window10下安裝 mysql5.7圖文教程(解壓版),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2016-08-08

最新評論

贺兰县| 拉孜县| 海林市| 衡南县| 北京市| 峡江县| 曲阳县| 温泉县| 浮山县| 遂宁市| 古交市| 肇东市| 信丰县| 沁阳市| 河津市| 阳信县| 江口县| 阿图什市| 建德市| 乌什县| 平乐县| 西青区| 瑞昌市| 巩义市| 宁陵县| 长治市| 宜州市| 汝城县| 鄂伦春自治旗| 沐川县| 金平| 高密市| 镇坪县| 新疆| 新昌县| 克拉玛依市| 乌拉特中旗| 鹿泉市| 上犹县| 邳州市| 和田市|