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

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

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

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

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

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

1.1 建表語(yǔ)句與存儲(chǔ)過(guò)程

-- 切換數(shù)據(jù)庫(kù)(需提前創(chuàng)建martin庫(kù):create database martin;)
use martin;
-- 1. 創(chuàng)建InnoDB引擎表t1(含主鍵+二級(jí)索引)
drop table if exists t1; 
CREATE TABLE `t1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `a` int DEFAULT NULL,  -- 允許為null,用于測(cè)試count(字段)
  `b` int NOT NULL,
  `c` int DEFAULT NULL,
  `d` int DEFAULT NULL,
  PRIMARY KEY (`id`),    -- 聚簇索引
  KEY `idx_a` (`a`),     -- 二級(jí)索引
  KEY `idx_b` (`b`)      -- 二級(jí)索引
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 2. 創(chuàng)建批量插入10000條數(shù)據(jù)的存儲(chǔ)過(guò)程
drop procedure if exists insert_t1; 
delimiter ;;  -- 臨時(shí)修改語(yǔ)句結(jié)束符,避免與存儲(chǔ)過(guò)程中的;沖突
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無(wú)null
set i=i+1; 
end while;
end;;
delimiter ;  -- 恢復(fù)語(yǔ)句結(jié)束符
-- 3. 執(zhí)行存儲(chǔ)過(guò)程+補(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);
-- 此時(shí)t1共10002行數(shù)據(jù),其中1行a為null
-- 4. 創(chuàng)建MyISAM引擎表t2(結(jié)構(gòu)與t1一致,用于對(duì)比引擎差異)
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)建無(wú)二級(jí)索引的InnoDB表t3(用于測(cè)試索引對(duì)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)識(shí)count(*):4個(gè)核心疑問(wèn)解答

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

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

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

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

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

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

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

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

執(zhí)行計(jì)劃對(duì)比

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

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

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

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

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

若表無(wú)二級(jí)索引(如t3表),則仍會(huì)掃描聚簇索引。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

-- 直接獲取Redis中的值,耗時(shí)微秒級(jí)
get t1_count;

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

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

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

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

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

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

-- 插入數(shù)據(jù)時(shí),在同一事務(wù)中更新計(jì)數(shù)
begin;  -- 開(kāi)啟事務(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ù)時(shí)同理
begin;
delete from t1 where id=10003;
update count_t1 set count=count-1 where table_name='t1';
commit;

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

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

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

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

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

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

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

相關(guān)文章

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

    基于MySQL文件排序用法解讀

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

    Navicat連接mysql報(bào)錯(cuò)1251錯(cuò)誤的解決方法

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

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

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

    Centos7下MySQL安裝教程

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

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

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

    MySQL 自增 ID 超過(guò) int 最大值的問(wèn)題解決

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

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

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

    Mysql常用sql語(yǔ)句匯總

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

    mysql存儲(chǔ)過(guò)程之返回多個(gè)值的方法示例

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

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

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

最新評(píng)論

嘉义县| 和龙市| 广汉市| 东乌珠穆沁旗| 奇台县| 东城区| 什邡市| 合肥市| 嘉禾县| 伊通| 辽阳县| 海城市| 闻喜县| 岳普湖县| 金寨县| 湖口县| 吉首市| 千阳县| 福建省| 梨树县| 海宁市| 闻喜县| 巍山| 柏乡县| 肃北| 台南市| 湘西| 开远市| 台山市| 赤峰市| 柯坪县| 皮山县| 新民市| 崇信县| 高雄市| 武隆县| 宁陵县| 白沙| 芦溪县| 苍溪县| 平潭县|