SQL詳細語法教程(七)核心優化

以下對?SQL 優化?涉及的關鍵場景(含?update?行鎖優化)進行極致詳細的拆解,從底層原理、執行流程到實戰代碼、避坑指南全維度覆蓋,搭配表格對比讓邏輯更清晰:

一、SQL 優化 - COUNT 優化

1. 底層原理:COUNT()?的執行邏輯本質

COUNT()?是?“統計符合條件的非 NULL 行數”,但不同寫法會觸發數據庫不同的執行路徑,核心差異在于?“是否利用索引”?和?“如何處理 NULL 值”

2. 細分場景對比(含執行流程、性能、適用場景)
語法寫法執行流程拆解(以 InnoDB 為例)性能關鍵影響點適用場景極端案例對比(1000 萬行表)
COUNT(*)1. 選最窄索引(如主鍵索引、普通索引)
2. 遍歷索引樹,統計 “非刪除標記” 的葉子節點數
3. 無需回表(因索引已記錄行數邏輯)
無需判 NULL,依賴優化器選最優索引全表 / 條件總行數統計耗時~100ms(走索引)
COUNT(1)與?COUNT(*)?邏輯幾乎等價,數據庫將?1?視為 “常量”,同樣走索引統計與?COUNT(*)?性能無差異(語法糖)習慣寫法,兼容所有場景耗時~100ms(同?COUNT(*)
COUNT(主鍵)1. 遍歷主鍵索引樹(聚簇索引)
2. 統計主鍵非 NULL 的行數(主鍵本身非 NULL,所以等價全表行統計)
主鍵必須存在,否則退化為全表掃描主鍵明確且需精準統計時耗時~120ms(主鍵索引稍寬)
COUNT(普通列)1. 遍歷普通索引(若列無索引則全表掃描)
2. 逐行判斷列值是否為 NULL,非 NULL 才計數
3. 若列有 NULL,需回表確認行狀態
需判 NULL + 可能回表,性能極差絕對禁止使用耗時~10s(全表掃 + 判空)
3. 實戰優化:從反例到正例
-- 反例 1:用 COUNT(name),name 可能為 NULL,且無索引時全表掃
-- 執行流程:全表掃描每一行 → 判 name 是否為 NULL → 統計非 NULL 值
SELECT COUNT(name) FROM t_user; -- 正例 1:全表行數統計,讓優化器自動選最窄索引(如 idx_status)
SELECT COUNT(*) FROM t_user; -- 反例 2:帶條件但無索引,觸發全表掃
SELECT COUNT(*) FROM t_user WHERE age > 18; -- 正例 2:給 age 加索引,讓數據庫走索引樹統計(無需回表)
CREATE INDEX idx_age ON t_user(age); 
SELECT COUNT(*) FROM t_user WHERE age > 18; -- 進階優化:高頻統計“某狀態行數”,用冗余字段/單獨表存儲
-- 場景:需實時統計 status=1 的行數,直接查冗余字段
ALTER TABLE t_user ADD COLUMN status_count INT DEFAULT 0; 
-- 插入/更新時維護 status_count,查詢時直接 SELECT status_count FROM t_user WHERE status=1;

二、SQL 優化 - 插入數據優化

1. 插入性能瓶頸:從磁盤 IO 到索引維護

插入操作的核心消耗是?“寫數據頁”?和?“維護索引”,具體流程:

  1. 事務日志(Redo Log):插入前先寫日志(確保崩潰恢復),磁盤隨機 IO 是瓶頸。
  2. 數據頁寫入:數據寫入內存頁,若頁未滿需等待(或觸發頁分裂)。
  3. 索引維護:每條數據需更新所有索引樹(如主鍵索引、普通索引),索引越多,耗時越久。
2. 細分場景優化(含代碼示例、參數調整)
插入場景核心問題優化手段代碼示例 / 參數調整性能提升對比(10 萬條數據)
單行插入(高頻)事務提交次數多,日志刷盤頻繁批量插入 + 調整事務提交策略```sql
-- 反例:單行插入(100 次事務)
INSERT INTO t_log (user_id, content) VALUES (1, 'a');
-- 正例:批量插入(1 次事務)
INSERT INTO t_log (user_id, content) VALUES (1, 'a'), (2, 'b'), ..., (1000, 'z');
```
MySQL 調整:SET autocommit = 0;(關閉自動提交)
從 10s → 1s 左右
高并發插入自增主鍵鎖競爭(AUTO_INCREMENT 鎖)用分布式 ID 或調整自增鎖模式```sql
-- 方案 1:雪花算法生成主鍵(Java 示例)
Long id = SnowflakeIdGenerator.nextId();
INSERT INTO t_order (id, user_id) VALUES (id, 123);
-- 方案 2:MySQL 調整自增鎖模式(適合批量插入)
SET GLOBAL innodb_autoinc_lock_mode = 2; -- 異步分配自增 ID
| 索引過多插入      | 索引維護耗時占比高(如 5 個索引)  | 先刪索引,插入后重建              | ```sql
-- 步驟 1:刪除索引
DROP INDEX idx_user ON t_order; 
DROP INDEX idx_create_time ON t_order; 
-- 步驟 2:批量插入(無索引維護開銷)
INSERT INTO t_order (...) VALUES (...); 
-- 步驟 3:重建索引
CREATE INDEX idx_user ON t_order(user_id); 
CREATE INDEX idx_create_time ON t_order(create_time); 
``` | 插入耗時從 30s → 5s        |  #### 3. 極端場景:冷熱數據分離插入  
```sql
-- 問題:歷史表(如 3 年前的訂單)插入時,因數據頁分散,插入慢
-- 優化:分區表+按時間分區,插入時直接定位到“熱分區”
ALTER TABLE t_order PARTITION BY RANGE (TO_DAYS(create_time)) (PARTITION p2023 VALUES LESS THAN (TO_DAYS('2024-01-01')),PARTITION p2024 VALUES LESS THAN (TO_DAYS('2025-01-01')),PARTITION p2025 VALUES LESS THAN (MAXVALUE)
); 
-- 插入時自動路由到對應分區,減少數據頁碎片影響
INSERT INTO t_order (create_time, ...) VALUES ('2024-06-01', ...); -- 走 p2024 分區

三、SQL 優化 - 主鍵優化

1. 主鍵設計的核心矛盾:“唯一性” vs “插入性能” vs “索引緊湊性”

主鍵是表的 “根索引”(InnoDB 聚簇索引),其設計直接影響?插入順序性(是否導致頁分裂)和?查詢效率(索引樹高度)。

2. 主鍵類型對比(含底層存儲、優缺點、適用場景)
主鍵方案底層存儲特點(InnoDB)優點缺點適用場景極端案例(10 億數據)
自增主鍵(INT)數據頁順序寫入,索引樹緊湊(類似數組 append)插入性能高,索引樹高度低(查詢快)高并發下自增鎖可能成為瓶頸中小規模業務、讀多寫少主鍵占 4B,索引樹高度~3(快)
分布式 ID(雪花算法)主鍵隨機不連續,但全局唯一(如 64 位 Long)無鎖競爭,支持超高并發插入索引樹碎片化(隨機寫導致頁分裂)海量數據、高并發寫入場景主鍵占 8B,索引樹高度~4(稍慢)
UUID 主鍵主鍵完全隨機(128 位字符串)全局唯一,無需依賴數據庫索引樹碎片化嚴重(插入性能暴跌)絕對禁止使用主鍵占 36B,索引樹高度~5(極慢)
3. 主鍵優化實操(解決索引碎片、鎖競爭)
-- 問題 1:刪除+插入頻繁,主鍵索引碎片化(查詢變慢)
-- 步驟 1:查看索引碎片率(MySQL)
SELECT TABLE_NAME, INDEX_NAME, INDEX_TYPE, DATA_FREE -- 碎片大小
FROM INFORMATION_SCHEMA.STATISTICS 
WHERE TABLE_SCHEMA = 'test_db' AND TABLE_NAME = 't_user'; -- 步驟 2:整理碎片(InnoDB 會重建聚簇索引)
OPTIMIZE TABLE t_user; -- 步驟 3:重建后查看碎片(DATA_FREE 大幅減少)
SELECT ...(同上); -- 問題 2:自增主鍵高并發鎖競爭
-- 方案:調整自增鎖模式(MySQL 8.0+)
SET GLOBAL innodb_autoinc_lock_mode = 2; -- 異步分配自增 ID,減少鎖等待
-- 注意:需確保 binlog 格式為 ROW(避免主從同步問題)

四、SQL 優化 - UPDATE 優化(避免行鎖升級為表鎖)

1. 鎖機制底層邏輯:行鎖 → 間隙鎖 → 表鎖的升級
  • 行鎖(Record Lock):僅鎖定匹配條件的行,需?WHERE?條件命中唯一索引(如主鍵、唯一索引)。
  • 間隙鎖(Gap Lock):鎖定索引區間(防止幻讀),若條件用范圍查詢(如?age > 18)且無唯一索引,會觸發間隙鎖。
  • 表鎖(Table Lock):若條件無索引,數據庫會全表掃描 + 鎖表,阻塞所有操作。
2. 行鎖優化:從反例到正例(含執行計劃分析)
-- 反例 1:無索引,觸發全表掃+表鎖
-- 執行計劃:type = ALL(全表掃),rows = 1000000(掃描 100 萬行)
UPDATE t_order SET status=1 WHERE create_time < '2023-01-01'; -- 正例 1:給 create_time 加索引,觸發行鎖(僅鎖匹配行)
-- 執行計劃:type = range(索引范圍掃),rows = 1000(掃描 1000 行)
CREATE INDEX idx_create_time ON t_order(create_time); 
UPDATE t_order SET status=1 WHERE create_time < '2023-01-01'; -- 反例 2:批量更新無 LIMIT,鎖太多行導致阻塞
UPDATE t_order SET status=1 WHERE status=0; -- 若 status=0 有 10 萬行,鎖競爭嚴重-- 正例 2:拆分批量更新,控制每次鎖的行數
-- 每次更新 100 行,循環執行直到完成
WHILE (1=1) DO UPDATE t_order SET status=1 WHERE status=0 LIMIT 100; IF ROW_COUNT() = 0 THEN LEAVE; END IF; -- 無更新時退出
END WHILE; -- 進階優化:顯式縮短事務時間(減少鎖持有時間)
BEGIN;
UPDATE t_order SET status=1 WHERE id=123; -- 走主鍵索引,行鎖
COMMIT; -- 立即釋放鎖,不阻塞其他操作
3. 鎖升級監控與排查(MySQL 為例)
-- 查看當前鎖等待情況
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS; 
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS; -- 定位慢更新 SQL(結合慢查詢日志)
-- 慢查詢日志配置:
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1 -- 超過 1 秒的 SQL 記錄

五、總結:SQL 優化的核心邏輯

所有優化本質圍繞?“減少 IO 次數、縮小鎖范圍、讓索引高效命中”?展開,關鍵是理解數據庫執行計劃(如?EXPLAIN),識別以下問題:

  1. COUNT:是否觸發全表掃、是否判 NULL;
  2. 插入:是否批量提交、是否索引過多;
  3. 主鍵:是否選對類型、是否有碎片;
  4. UPDATE:是否走索引、是否鎖范圍過大。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/93797.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/93797.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/93797.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Tomcat 的核心腳本catalina.sh 和 startup.sh的關系

catalina.sh 和 startup.sh 都是 Tomcat 的核心腳本&#xff0c;但它們的角色和使用場景有所不同。以下是它們的主要區別和適用場景&#xff1a;1. 功能區別腳本主要用途底層調用關系startup.sh一個快捷入口腳本&#xff0c;用于快速啟動 Tomcat&#xff08;后臺模式&#xff0…

飛算JavaAI:簡易貪吃蛇小游戲

目錄先確定核心功能技術選型核心功能實現過程1. 數據模型設計2. 游戲界面和繪制邏輯3. 游戲主框架和事件處理飛算JavaAI在開發中的應用體驗可以進一步優化的地方作為Java課程的小作業&#xff0c;不想做太復雜的管理系統&#xff0c;就選了貪吃蛇這個經典小游戲。全程用Swing做…

如何保障內部網絡安全前提下,實現與外部互聯網之間的文件傳輸?

在數字化時代&#xff0c;企業網絡環境日益復雜&#xff0c;普遍采用“內外網隔離”的安全架構&#xff1a;內部辦公網承載業務系統與數據&#xff0c;外部互聯網則用于對外溝通與信息獲取。這種隔離有效抵御了外部攻擊&#xff0c;但也帶來了“信息孤島”問題——如何在保障內…

計算機視覺 圖片處理 在骨架化過程中,每次迭代都會從圖像的邊緣移除一層像素,直到只剩下單像素寬度的骨架

你說得對&#xff0c;if cv2.countNonZero(binary) 0: break 這個條件確實表示圖像中已經沒有非零像素&#xff0c;即圖像完全變為空白。這并不是骨架化完成的標志&#xff0c;而是表示圖像已經被腐蝕到沒有任何內容了。 在骨架化過程中&#xff0c;我們需要一個更合適的停止條…

rt-thread audio框架移植stm32 adc+dac,用wavplayer錄音和播放

D1 參考 rt-thread官方sdk中&#xff0c;正點原子stm32f429-atk-appollo的board中有audio文件夾&#xff0c;包括了mic/play的程序&#xff0c;wm8978的庫文件因為我們基于stm32h750內置adcdac設計&#xff0c;所以不需要wm8978.c/h。只需要移植drv_sound.c和drv_mic.c D2 工程…

AI重塑軟件測試:質量保障的下一站

軟件開發的世界變化飛快&#xff0c;系統越來越復雜&#xff0c;用戶的胃口越來越大&#xff0c;產品上線的壓力也越來越大。作為測試工程師&#xff0c;你是不是常常覺得傳統測試已經跟不上節奏了&#xff1f;手工測試累死人&#xff0c;自動化腳本維護到崩潰&#xff0c;測試…

【前端基礎知識系列六】React 項目基本框架及常見文件夾作用總結(圖文版)

在 React 開發中&#xff0c;一個清晰合理的項目結構不僅能提高開發效率&#xff0c;還能讓代碼更易于維護和擴展。尤其是在團隊協作中&#xff0c;統一的項目結構規范至關重要。本文將通過圖文結合的方式&#xff0c;詳細介紹 React 項目的基本框架以及常見文件夾的定義與作用…

0815 UDP通信協議TCP并發服務器

Part 1.思維導圖一.UDP通信協議1.原理服務器端&#xff1a;1.用socket函數創建一個套接字文件2.創建服務器端地址結構體并賦值3.用ford函數將套接字文件與地址結構體綁定4.創建接收客戶端地址結構體5.利用sendto和recvfrom函數傳輸和接收信息客戶端&#xff1a;1.用socket函數創…

一個基于純前端技術實現的五子棋游戲,無需后端服務,直接在瀏覽器中運行。

一 功能特性1.1 核心游戲功能- **標準五子棋規則**&#xff1a;1515棋盤&#xff0c;黑子(玩家)先手 - **AI對戰模式**&#xff1a;白子AI具有中等難度&#xff0c;會進行智能進攻和防守 - **勝負判定**&#xff1a;支持橫向、縱向、斜向五子連線獲勝 - **平局檢測**&#xff1…

HBuilderX升級,Vue2 scss 預編譯器默認已由 node-sass 更換為 dart-sass

目錄 一、問題描述 二、問題原因 三、問題解析及解決方案 一、問題描述 最近開發新項目&#xff0c;升級了HBuilderX版本到4.75&#xff0c;最近要在之前的項目添加功能的時候發現報錯&#xff0c;錯誤如下&#xff1a;Vue2 scss 預編譯器默認已由 node-sass 更換為 dart-sa…

像素風球球大作戰 HTML 游戲

像素風球球大作戰 HTML 游戲 下面是一個簡單的像素風格球球大作戰 HTML 游戲代碼&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-widt…

文件導出時無法獲取響應頭Content-Disposition的文件名

1. 為什么Content-Disposition無法獲取&#xff1f; 要拿到 Content-Disposition 里的 filename&#xff0c;可以用正則或者簡單的字符串解析。 瀏覽器默認不讓前端訪問非標準響應頭&#xff0c;Content-Disposition 需要后端顯式暴露。 在瀏覽器開發者工具 → Network → Re…

Leetcode 128. 最長連續序列 哈希

原題鏈接&#xff1a; Leetcode 128. 最長連續序列 解法1: map&#xff0c;不符合要求 class Solution { public:int longestConsecutive(vector<int>& nums) {if (nums.size()0) return 0;map<int,int> mp;for(auto x: nums){mp[x];}int pre;int l0,r0,res0;…

禾賽激光雷達AT128P/海康相機(2):基于歐幾里德聚類的激光雷達障礙物檢測

目錄 一、參考連接 二、實驗效果?編輯 三、安裝相應的 ros 依賴包 四、代碼驅動 4.1 代碼下載 4.2 代碼文件放置(請按照這個命名放置代碼) 4.3 代碼編譯 4.4 報錯 一、參考連接

Vue Router的常用API有哪些?

文章目錄一、路由配置相關二、路由實例方法&#xff08;router 實例&#xff09;三、組件內路由 API&#xff08;useRouter / useRoute&#xff09;四、導航守衛&#xff08;路由攔截&#xff09;五、路由視圖與導航組件六、其他常用 API七、history模式和hash模式有什么區別&a…

從現場到云端的“通用語”:Kepware 在工業互聯中的角色、使用方法與本土廠商(以胡工科技為例)的差異與優勢

從現場到云端的“通用語”&#xff1a;Kepware 在工業互聯中的角色、使用方法與本土廠商&#xff08;以胡工科技為例&#xff09;的差異與優勢 文章目錄從現場到云端的“通用語”&#xff1a;Kepware 在工業互聯中的角色、使用方法與本土廠商&#xff08;以胡工科技為例&#x…

深入理解Prompt構建與工程技巧:API高效實踐指南

深入理解Prompt構建與工程技巧&#xff1a;API高效實踐指南 引言 Prompt&#xff08;提示&#xff09;工程是推動大模型能力極限的關鍵手段。合理的Prompt不僅能顯著提升模型輸出的相關性與準確性&#xff0c;在實際落地的API接口開發中同樣起到舉足輕重的作用。本文將系統介…

C++之多態(從0到1的突破)

世間百態&#xff0c;每個人都扮演著不同的角色&#xff0c;都進行著不同的行為。C更是如此&#xff0c;C中也會出現有著不同行為的多種形態的出現&#xff0c;那就讓我們一起進入C的多態世界吧&#xff01;&#xff01;&#xff01; 一. 多態的概念 多態&#xff0c;顧名思義&…

路由器NAT的類型測定

目前所使用的NAT基本都是NAPT&#xff0c;即多端口的NAT技術&#xff0c;因此本文主要是設計了兩種測定路由器NAPT類型的實驗。 實驗環境 設備 主機A&#xff1a;Windows主機B&#xff1a;Windows路由器 軟件 ncWiresharkSocketTools 在局域網內部完成所有測試&#xff0c;完全…

ROS 2系統Callback Group概念筆記

核心概念 Callback Group&#xff08;回調組&#xff09;是一個管理一個或多個回調函數執行規則的容器。它決定了這些回調函數是如何被節點&#xff08;Node&#xff09;的 executor 調度的&#xff0c;特別是當多個回調函數同時就緒時&#xff0c;它們之間是并行執行還是必須串…