Skip to content

資料庫原理(索引 / 事務 / 查詢最佳化)

核心問題

為什麼你的 Excel 查詢要 10 秒,而淘寶搜尋只要 0.01 秒? 當資料從「幾千條」變成「十億條」,從「一人使用」變成「千萬人同時存取」,Excel 就不夠用了。資料庫就是為解決這個問題而生的——它是專門處理海量資料、高併發存取的「超級 Excel」。本章將帶你從零開始理解資料庫的核心原理。


1. 為什麼要「資料庫」?

1.1 從小書店到淘寶:資料規模的演變

想像你開了一家小書店,每天賣出幾本書。你隨手在筆記本上記下:

2024-01-15:張三買了《百年孤寂》,59元
2024-01-16:李四買了《活著》,39元

這時候,筆記本完全夠用。但當你的書店變成了「亞馬遜」,每天有百萬訂單湧入,問題就出現了:

  • 資料量大:不是幾十行,而是幾億行
  • 併發存取:不是一個人在查,而是幾千萬人同時存取
  • 資料關聯:訂單關聯使用者、商品、庫存、物流……複雜關係需要高效管理
  • 資料安全:不能因為斷電就遺失所有訂單

Excel / 筆記本

  • 適合個人或小團隊
  • 資料量:幾千到幾萬行
  • 單人使用,循序存取
  • 手動尋找,速度慢

資料庫

  • 適合企業級應用
  • 資料量:億級以上
  • 千萬人同時在線存取
  • 毫秒級查詢速度

這就是「資料庫」要解決的問題:如何高效儲存、快速查詢、安全地管理海量資料?

1.2 一個真實的踩坑故事:為什麼不能用 Excel 存使用者資料

你可能會說:「我的專案才幾萬使用者,Excel 不就夠用了嗎?」讓我講一個真實的故事。

小林的創業踩坑記

小林創業做了一個社交應用,剛開始使用者不多,他用 Excel 儲存使用者資訊(姓名、手機、註冊時間等)。每天匯出 Excel 統計使用者成長,一切正常。

當使用者突破 10 萬時,問題開始出現了:

  • Excel 開啟要等 5 分鐘
  • 篩選「台北的使用者」要卡頓半天
  • 有一次 Excel 檔案損毀,幾千個使用者資料永久遺失

最致命的是,他想要實作「查看某個使用者的所有訂單」這個功能——但使用者資訊和訂單分別在不同的 Excel 表裡,他只能手動複製貼上,每次都要花半小時。

後來他請教學長,學長看了一眼就笑了:「你需要的不是 Excel,而是資料庫。」

改用資料庫後,一切都變了:

  • 查詢「台北的使用者」只需要 0.01 秒
  • 透過「關聯」自動關聯使用者和訂單,一個 SQL 語句搞定
  • 資料自動備份,再也不怕檔案損毀

小林從此明白了一個道理:資料量小的時候,什麼都能用;但資料一大,Excel 就是災難。

核心啟示

資料庫不是「更複雜的 Excel」,而是完全不同的設計理念:

  • Excel:為小資料、單人使用設計
  • 資料庫:為大資料、高併發、複雜關聯設計

選擇合適的工具,能讓你的系統效能提升成千上萬倍。


2. 核心概念:表、行、列、主鍵

這些概念和資料庫有什麼關係?

表、行、列、主鍵就是資料庫的「積木塊」。

想像你要蓋房子:

  • = 一個房間(存放一類資料)
  • = 房間裡的一個箱子(一條完整記錄)
  • = 箱子上的標籤(姓名、年齡等)
  • 主鍵 = 箱子的唯一編號(絕對不會重複)

理解這些基礎概念,你才能知道資料是如何組織的。

在深入學習資料庫之前,我們需要先搞清楚這幾個核心概念。為了幫助你理解,我們用圖書館的比喻來類比。

2.1 用圖書館比喻理解資料庫結構

想像你走進一座圖書館,裡面的組織和資料庫驚人地相似:

概念圖書館比喻實際作用具體例子
資料庫 (Database)整座圖書館存放所有資料的容器一個電商網站的資料庫
表 (Table)一個書架存放同一類資料的集合使用者表、商品表、訂單表
列 (Column)書脊上的標籤資料的屬性(欄位)姓名、年齡、手機號
行 (Row)書架上的每一本書一條具體的資料記錄「張三,25歲,台北」
主鍵 (Primary Key)每本書的 ISBN 編號唯一識別每一行的 IDuser_id = 1001

看個真實例子:使用者表 (users)

user_id (主鍵)nameagecityemail
1001張三25台北zhangsan@example.com
1002李四30上海lisi@example.com
1003王五28台北wangwu@example.com
  • users(存放所有使用者資料)
  • user_idnameagecityemail(每個使用者的屬性)
  • :每一行是一個使用者(如「張三,25歲,台北」)
  • 主鍵user_id(1001、1002、1003,永不重複)

2.2 主鍵 (Primary Key):資料的「身分證號」

什麼是主鍵?

主鍵就是表中每一行的唯一識別,就像身分證號一樣。

關鍵特點

  • 唯一性:絕對不會重複(沒有兩個人有相同的身分證號)
  • 非空:必須有值(不可能有「沒有身分證號」的人)
  • 不變性:一旦設定,不會修改(你的身分證號不會變)

常見的做法

  • 使用自增整數:1、2、3、4...
  • 使用 UUID(全球唯一識別碼):550e8400-e29b-41d4-a716-446655440000

為什麼需要主鍵?想像一下沒有主鍵的世界:

場景:你想修改「張三」的年齡,但表裡有 3 個「張三」,系統該改哪一個?

sql
-- 沒有主鍵,這會同時修改所有叫「張三」的人!
UPDATE users SET age = 26 WHERE name = '張三';

-- 有主鍵,精確修改
UPDATE users SET age = 26 WHERE user_id = 1001;

主鍵的黃金法則:每個表都應該有一個主鍵,而且永遠不要修改它。

2.3 外鍵 (Foreign Key):連接表的橋樑

這是資料庫比 Excel 強大的關鍵——表之間可以建立關聯

什麼是外鍵?

外鍵是指向另一張表主鍵的列,用來建立表與表之間的關聯。

簡單理解

  • 主鍵 = 我的身分證號
  • 外鍵 = 我引用的別人的身分證號

舉個例子:訂單表裡的 user_id 就是外鍵,它指向使用者表的主鍵。

看一個真實的例子:

使用者表 (users)

user_id (主鍵)namephone
1001張三138xxxx
1002李四139xxxx

訂單表 (orders)

order_id (主鍵)product_namepriceuser_id (外鍵)
5001iPhone 1559991001
5002MacBook149991001
5003AirPods19991002

關鍵理解

  • 訂單表裡的 user_id = 1001 指向使用者表裡的 user_id = 1001(張三)
  • 當你要查「訂單 5001 是誰買的」,資料庫會自動去使用者表查找 user_id = 1001 的使用者

好處

  • 資料不重複:張三買 100 單商品,他的資訊也只在使用者表存一次
  • 易於維護:張三換手機號,只改使用者表,所有訂單自動關聯新手機號
  • 靈活查詢:可以輕鬆回答「每個使用者的總消費是多少」這類複雜問題
🔗外键关系演示理解表与表之间如何关联
想象你在管理一个家族谱系:有"家谱表"记录每个人,有"婚姻表"记录谁和谁结婚了。两张表通过"人名"关联起来,这就是外键的作用。
👥用户表 (users)主表
🔑 user_id
name
phone
address
101
张三
138xxxx
北京
102
李四
139xxxx
上海
103
王五
137xxxx
广州
user_id (外键) → user_id (主键)
📦订单表 (orders)从表
🔑 order_id
book_name
🔗 user_id
price
001
百年孤独
101
59
002
活着
101
39
003
三体
101
99
004
百年孤独
102
59
005
红楼梦
102
79
006
西游记
103
69
💡 核心概念

主键(Primary Key):用户表的 user_id 是主键,唯一标识每个用户。

外键(Foreign Key):订单表的 user_id 是外键,指向用户表的主键。

关联查询:通过外键,数据库可以快速找到"订单 001 是用户 101 买的",然后去用户表查到"用户 101 是张三"。

🎯核心优势:外键消除了数据冗余。张三的地址只存一次,无论他买多少本书。如果要修改地址,只需改用户表的一行,所有订单自动关联到新地址。

3. 如何和資料庫對話?SQL 入門與實戰

你不能直接用滑鼠「點」資料庫(雖然有圖形化工具,但本質也是轉換成指令),你需要用一種特殊的語言來指揮資料庫工作。

這種語言就是 SQL (Structured Query Language,結構化查詢語言)

好訊息是:SQL 非常接近自然英語,讀起來就像在說話。

3.1 SQL 的核心操作:CRUD

大部分時候,你只需要掌握四種操作,江湖人稱 CRUD

操作英文SQL 關鍵字通俗理解
Create建立INSERT新增一筆資料
Read讀取SELECT查詢資料
Update更新UPDATE修改資料
Delete刪除DELETE刪除資料

從表格中你能看到什麼?

這四個操作涵蓋了資料處理的全部場景:

  • Create:使用者註冊時,插入一筆新使用者記錄
  • Read:使用者登入時,查詢使用者名稱和密碼
  • Update:使用者修改個人資料時,更新表中的資料
  • Delete:使用者註銷帳號時,刪除使用者資料

記住這四個,你就掌握了 80% 的日常 SQL 操作。

3.2 查詢資料 (SELECT):資料庫最常用的操作

查詢是資料庫最重要的功能,也是效能最佳化的關鍵。

示例 1:查找所有台北的使用者

sql
SELECT name, age FROM users WHERE city = '台北';

逐詞理解

  • SELECT name, age:選擇 name 和 age 這兩列
  • FROM users:從 users 這張表
  • WHERE city = '台北':在 city 等於「台北」的條件下

回傳結果

nameage
張三25
王五28

示例 2:查找價格在 5000 到 15000 之間的商品

sql
SELECT name, price FROM products
WHERE price BETWEEN 5000 AND 15000;

示例 3:模糊搜尋(查找名字包含「張」的使用者)

sql
SELECT name FROM users WHERE name LIKE '%張%';

效能陷阱:LIKE 的使用

LIKE '%張%' 會導致全表掃描,資料量大時非常慢。

最佳化建議

  • 不要用 LIKE '%張%'(前後都有 %)
  • 可以用 LIKE '張%'(只有後面有 %)

因為 LIKE '張%' 可以利用索引,而 LIKE '%張%' 無法使用索引。

3.3 插入資料 (INSERT):新增記錄

示例:新增一個使用者

sql
INSERT INTO users (user_id, name, age, city, email)
VALUES (1004, '趙六', 35, '高雄', 'zhaoliu@example.com');

逐詞理解

  • INSERT INTO users:插入到 users 表
  • (user_id, name, age, city, email):指定要插入的列
  • VALUES (1004, '趙六', ...):對應的值

批量插入(更高效):

sql
INSERT INTO users (name, age, city) VALUES
('小明', 25, '台北'),
('小紅', 28, '上海'),
('小剛', 30, '高雄');

3.4 更新資料 (UPDATE):修改記錄

示例:給所有台北的使用者年齡加 1

sql
UPDATE users SET age = age + 1 WHERE city = '台北';

非常危險:別忘了 WHERE!

如果你忘記寫 WHERE 子句,會修改所有行

sql
-- 危險!會把所有使用者的年齡都改成 26
UPDATE users SET age = 26;

-- 正確:只修改 user_id = 1001 的使用者
UPDATE users SET age = 26 WHERE user_id = 1001;

真實教訓:2012 年,某知名公司因為工程師忘記寫 WHERE,導致正式環境數百萬使用者資料被錯誤更新,系統癱瘓 4 小時,損失巨大。

3.5 刪除資料 (DELETE):刪除記錄

示例:刪除 user_id = 1004 的使用者

sql
DELETE FROM users WHERE user_id = 1004;

雙重危險:DELETE 更需要 WHERE!

sql
-- 危險!會刪除整張表的所有資料!
DELETE FROM users;

-- 正確:只刪除指定行
DELETE FROM users WHERE user_id = 1004;

最佳實踐

  1. 刪除前先用 SELECT 確認資料
  2. 在重要系統中,使用「軟刪除」(新增 is_deleted 欄位標記刪除)
  3. 正式環境操作前先備份資料

3.6 多表查詢 (JOIN):資料庫的魔法時刻

還記得我們講過的「外鍵」嗎?SQL 最強大的地方在於可以一次性查詢多張關聯的表。

場景:查詢「張三買過的所有商品」

假設我們有三張表:

使用者表 (users)

user_idname
1001張三

商品表 (products)

product_idnameprice
201iPhone 155999
202MacBook14999

訂單表 (orders)

order_iduser_idproduct_idquantity
500110012011
500210012022

SQL 查詢

sql
SELECT u.name, p.name AS product_name, p.price, o.quantity
FROM orders o
JOIN users u ON o.user_id = u.user_id
JOIN products p ON o.product_id = p.product_id
WHERE u.name = '張三';

回傳結果

nameproduct_namepricequantity
張三iPhone 1559991
張三MacBook149992

理解 JOIN 的過程

  1. FROM orders o:從訂單表開始
  2. JOIN users u ON o.user_id = u.user_id:透過 user_id 關聯使用者表
  3. JOIN products p ON o.product_id = p.product_id:透過 product_id 關聯商品表
  4. WHERE u.name = '張三':篩選張三的訂單
💻SQL 练习场体验 SQL 的 CRUD 操作
SQL 就像和数据库对话:你说"给我找所有年龄大于 25 的用户",数据库就会执行查询并返回结果。即使不会编程,也能很快上手。
📝 示例 SQL
SELECT name, age FROM users WHERE age > 25;
💡 逐词翻译
SELECT name, age选择 name 和 age 这两列
FROM users从 users 这张表
WHERE age > 25在 age 大于 25 的条件下
📊 返回结果
name
age
李四
30
王五
28
🎯核心概念:CRUD 涵盖了所有数据管理的基本需求。无论是淘宝、微信、抖音,它们的数据库操作本质上就是这四种:增、删、改、查。

4. 為什麼資料庫這麼快?索引原理揭密

這是資料庫最神奇的地方,也是面試中最愛問的問題。

如果你在 Excel 裡查找「所有姓張的人」,Excel 需要從第一行掃到最後一行。這就是全表掃描——資料越多,速度越慢。

但在資料庫裡,即使有 10 億行資料,查找也只需要幾毫秒。

秘訣就是:索引 (Index)。

4.1 直觀理解:字典的啟示

想像你要在一本沒有目錄的 1000 頁書裡找一個詞。你該怎麼辦?

只能一頁一頁翻——這就是全表掃描,平均需要翻 500 頁。

但如果這本書有注音索引呢?

你要找「資料庫」這個詞:

  1. 翻到索引,找到「資」字開頭的區域
  2. 在「資」字區域內,找「料」字
  3. 索引告訴你:在第 256 頁

你只需要翻 3 次就能找到!這就是索引查找

資料庫的索引就像書的目錄

  • 沒有索引:逐行掃描(10 億行 = 數分鐘)
  • 有索引:直接跳轉(10 億行 = 3 次磁碟 I/O = 幾毫秒)

4.2 全表掃描 vs 索引查找:速度對比

假設我們有一張使用者表,有 1000 萬條記錄。

場景:查找 user_id = 5,555,555 的使用者

方式過程需要檢查的行數耗時估算
全表掃描從第 1 行開始,一行一行看平均 500 萬行5-30 秒
索引查找查索引樹,直接跳到目標位置3-4 次比較0.003 秒

速度差距:數千倍!

核心啟示

索引不是銀彈,它有代價:

  • 佔用空間:索引需要額外的儲存空間
  • 降低寫入速度:每次 INSERT/UPDATE/DELETE 都要更新索引

什麼時候建索引?

  • 經常用來查詢的列(WHERE、JOIN 的條件)
  • 資料量大(幾千行以下不需要)

什麼時候不建索引?

  • 很少查詢的列
  • 頻繁更新的列
  • 資料量小的表

4.3 底層資料結構:B+ 樹

真實的索引不是簡單的「字母列表」,而是一種精心設計的資料結構,叫做 B+ 樹 (B+ Tree)

什麼是 B+ 樹?

B+ 樹是一種「矮胖」的樹形資料結構:

  • :從根到葉子通常只有 3-4 層
  • :每個節點可以儲存幾百個鍵值

為什麼要「矮胖」?

因為資料儲存在磁碟上,每次讀取磁碟(I/O)都非常慢(比記憶體慢幾千倍)。B+ 樹的設計目標就是盡量減少磁碟 I/O 次數

  • 3-4 層高度 = 最多 3-4 次磁碟讀取
  • 每層存大量資料 = 保證樹不會太高

真實例子

假設一棵 B+ 樹的每個節點可以儲存 1000 個鍵值:

  • 根節點:1000 個鍵值 → 指向 1000 個子節點
  • 中間節點:每個存 1000 個鍵值 → 指向 1000 個葉子節點
  • 葉子節點:每個存 1000 條真實資料

總資料量 = 1000 × 1000 × 1000 = 10 億條資料

樹的高度 = 3 層

這意味著:在 10 億條資料中查找任意一條,只需要 3 次磁碟 I/O

這就是資料庫查詢飛快的秘密。

🌳B+ 树索引演示理解数据库如何快速查找数据
想象你要在字典里找一个字。你会先看目录,定位到首字母的区域,再在这个区域里找具体页码。B+ 树就是这样的多层目录,让数据库在 10 亿条数据中 3 次就能找到目标。
🐢全表扫描
001用户1
002用户2
003用户3
004用户4
005用户5
006用户6
007用户7
008用户8
009用户9
010用户10
011用户11
012用户12
013用户13
014用户14
015用户15
016用户16
017用户17
018用户18
019用户19
020用户20

👆 点击"开始查找"看全表扫描有多慢

索引查找
根节点
1-100
中间节点
1-10
叶子节点
1
2
3
4
5
6
7
8
9
10

👆 点击"开始查找"看索引有多快

数据量
100 万条
全表扫描
平均 50 万次比较
B+ 树索引
仅 3 次比较
速度提升
10 万倍+
💡核心原理:B+ 树通过"矮胖"的设计,让树的高度只有 3-4 层。每层可以存储成百上千个键值,所以 10 亿数据也只需要 3 次磁盘 I/O。这就是数据库查询飞快的秘密。

5. 事務:如何保證資料不丟、不亂?

想像一下春運搶票的場景:

  • 時間 T1:使用者 A 查詢,發現「G1234 次列車還剩 1 張票」
  • 時間 T2:使用者 B 也查詢,也發現「還剩 1 張票」
  • 時間 T3:使用者 A 點擊「購買」,系統扣庫存,票賣給了 A
  • 時間 T4:使用者 B 點擊「購買」——如果沒有保護機制,系統會再次扣庫存,把同一張票賣給 B!

這就是典型的併發衝突問題。

5.1 什麼是事務 (Transaction)?

事務是資料庫的一組操作,這些操作要麼全部成功,要麼全部失敗,不會出現「做了一半」的情況。

生活中的例子

銀行轉帳就是一個典型的事務:

  1. 從帳戶 A 扣除 100 元
  2. 給帳戶 B 增加 100 元

如果第 1 步成功了,但第 2 步失敗了(比如斷電),會發生什麼?

  • 沒有事務:帳戶 A 的錢沒了,帳戶 B 沒收到錢,錢 憑空消失了
  • 有事務:系統發現第 2 步失敗,自動回滾第 1 步,兩個帳戶都恢復原狀

這就是事務的原子性:要麼全做,要麼全不做。

5.2 事務的四大特性 (ACID)

事務有四大特性,簡稱 ACID

特性英文含義銀行轉帳的例子
Atomicity原子性要麼全做,要麼全不做扣款和入帳必須同時成功,不能只扣錢不入帳
Consistency一致性資料始終保持合法狀態轉帳前後,兩個帳戶的總金額應該不變
Isolation隔離性多個事務互不影響A 在轉帳時,B 看到的應該是「轉帳前」或「轉帳後」的餘額,不能看到中間狀態
Durability持久性一旦提交,資料永久儲存轉帳成功後,即使斷電,帳戶餘額也不會變回去

從表格中你能看到什麼?

這四個特性保證了資料的安全性:

  • 原子性:防止「做一半」(扣了錢但沒到帳)
  • 一致性:防止資料不合理(轉帳後總金額變了)
  • 隔離性:防止併發衝突(兩個人同時修改同一資料)
  • 持久性:防止資料遺失(提交後斷電也不影響)

沒有這些保證,銀行系統根本無法運行。

5.3 事務的隔離級別:權衡安全與效能

理論上,我們希望事務完全隔離。但完全隔離 = 效能極差(因為需要大量加鎖,其他事務只能等待)。

因此,資料庫提供了四種隔離級別

隔離級別髒讀不可重複讀幻讀效能適用場景
讀未提交可能可能可能最快幾乎不用(資料可能錯誤)
讀已提交不可能可能可能較快普通業務(Oracle 預設)
可重複讀不可能不可能可能中等銀行轉帳(MySQL 預設)
串行化不可能不可能不可能最慢極端嚴格場景(極少用)

三個「讀」是什麼意思?

  • 髒讀:讀到了其他事務還沒提交的資料(可能回滾,資料不準確)
  • 不可重複讀:同一事務裡,兩次讀同一資料,結果不一樣(被其他事務修改了)
  • 幻讀:同一事務裡,兩次查詢,結果集的行數不一樣(其他事務插入/刪除了資料)

通俗例子(銀行查餘額):

  • 髒讀:你查到餘額 1000 元,但對方事務回滾了,實際只有 100 元
  • 不可重複讀:你第一次查餘額 1000 元,第二次查變成 800 元(被扣款了)
  • 幻讀:你第一次查到 5 筆交易,第二次查變成 6 筆(新增了一筆)
🔒事务 ACID 特性演示理解事务如何保证数据安全
想象银行转账:A 转给 B 100 元。这个操作包含两步:从 A 扣 100,给 B 加 100。如果只扣了钱但没到账,就是灾难。事务保证这两步要么全成功,要么全失败
⚛️
A
原子性
Atomicity
⚖️
C
一致性
Consistency
🔒
I
隔离性
Isolation
💾
D
持久性
Durability
👆 点击上方任意特性,查看详细解释
🎯 12306 抢票场景

场景:用户 A 和 B 同时看到还剩 1 张票,同时点击购买。

没有事务:A 扣库存,B 也扣库存,同一张票卖给了两个人!

有事务(隔离性):A 的操作加锁,B 必须等待。A 买完后,库存变为 0,B 看到的是"已售罄"。

💡核心思想:ACID 四个特性共同保证了数据在高并发环境下的不丢、不乱、不冲突。这就是为什么所有涉及资金、订单的系统都必须使用数据库事务。

6. 效能最佳化:讓查詢快 1000 倍的實戰技巧

現在你已經理解了索引、事務這些核心概念。但在真實專案中,你可能會遇到各種效能問題。

本節將給出可直接落地的最佳化策略

6.1 索引使用避坑指南

常見錯誤:索引失效的坑

很多時候,你明明建了索引,但查詢還是很慢——因為索引失效了。

導致索引失效的常見原因

  1. 在索引列上使用函式
  2. 隱式類型轉換
  3. LIKE 查詢以 % 開頭
  4. OR 條件(部分情況)
  5. 複合索引不滿足最左前綴原則

坑 1:在索引列上使用函式

sql
-- 錯誤:對索引列使用函式,無法使用索引
SELECT * FROM users WHERE YEAR(created_at) = 2024;

-- 正確:改寫為範圍查詢,可以使用索引
SELECT * FROM users
WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';

坑 2:隱式類型轉換

sql
-- 假設 user_id 是 int 類型
-- 錯誤:傳字串,導致隱式轉換,無法使用索引
SELECT * FROM users WHERE user_id = '123';

-- 正確:傳對應類型
SELECT * FROM users WHERE user_id = 123;

坑 3:LIKE 以 % 開頭

sql
-- 錯誤:以 % 開頭,無法使用索引
SELECT * FROM users WHERE name LIKE '%張三%';

-- 正確:以固定前綴開頭,可以使用索引
SELECT * FROM users WHERE name LIKE '張三%';

-- 或者使用全文索引(適用於文字搜尋)
SELECT * FROM users WHERE MATCH(name) AGAINST('張三');

6.2 SQL 最佳化實戰模板

模板 1:分頁最佳化(深分頁問題)

查看問題與解決方案
sql
-- 問題:OFFSET 很大時,查詢越來越慢
SELECT * FROM orders
ORDER BY created_at DESC
LIMIT 10 OFFSET 1000000;

-- 最佳化方案 1:使用上次查詢的時間戳記作為游標
SELECT * FROM orders
WHERE created_at < '2024-01-15 12:00:00'
ORDER BY created_at DESC
LIMIT 10;

-- 最佳化方案 2:使用主鍵範圍查詢
SELECT * FROM orders
WHERE order_id > 1000000
ORDER BY order_id
LIMIT 10;

模板 2:批量插入最佳化

sql
-- 低效:多次單條插入(網路往返多次)
INSERT INTO users (name, age) VALUES ('張三', 25);
INSERT INTO users (name, age) VALUES ('李四', 30);
INSERT INTO users (name, age) VALUES ('王五', 28);

-- 高效:單條 SQL 批量插入(只需一次網路往返)
INSERT INTO users (name, age) VALUES
('張三', 25),
('李四', 30),
('王五', 28);

**模板 3:避免 SELECT ***

sql
-- 低效:回傳所有列(包括不需要的大欄位)
SELECT * FROM users WHERE user_id = 1;

-- 高效:只回傳需要的列
SELECT user_id, name, email FROM users WHERE user_id = 1;

6.3 高併發場景應對策略

場景問題解決方案
熱點資料某行資料被頻繁讀寫,導致鎖競爭使用快取(Redis)+ 讀寫分離
秒殺場景瞬間高併發扣減庫存樂觀鎖 + 庫存預熱 + 訊息佇列削峰
慢查詢複雜查詢拖垮資料庫索引最佳化 + 查詢拆分 + 讀寫分離
連線數耗盡太多併發請求導致連線池耗盡連線池最佳化 + 限流 + 服務降級

核心啟示

效能最佳化的基本原則:

  1. 先測量,後最佳化:用 EXPLAIN 分析查詢計畫,找到真正的瓶頸
  2. 索引優先:80% 的效能問題都可以透過最佳化索引解決
  3. 減少資料庫壓力:能用快取就用快取,能非同步就非同步
  4. 分而治之:大表拆分成小表,大查詢拆分成小查詢
查询优化演示常见错误与正确做法对比
很多时候,查询慢不是因为数据库性能差,而是因为 SQL 写错了。下面这些错误,你可能每天都在犯。
1
在索引列上使用函数
SELECT * FROM users WHERE YEAR(created_at) = 2024;
⚠️ 索引失效,全表扫描
SELECT * FROM users WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01';
💡 可以使用索引,查询速度提升 1000 倍
原理:当对列使用函数时,数据库必须先计算每一行的函数值,无法使用索引。把函数移到等号右边,或用范围查询代替。
2
隐式类型转换
3
LIKE 以 % 开头
4
SELECT * 返回所有列
📝 优化建议清单
为 WHERE、JOIN、ORDER BY 的列创建索引
避免在索引列上使用函数或表达式
用 EXPLAIN 分析查询执行计划
只查询需要的列,避免 SELECT *
批量操作代替单条操作
考虑使用覆盖索引减少回表
🎯核心原则:不要让数据库做"多余的工作"。索引失效、全表扫描、返回不必要的数据,这些都是最常见的性能杀手。写出高效 SQL 的关键,是理解数据库如何执行你的查询

7. 總結與學習路線

讓我們用一張表格來回顧資料庫的核心概念:

概念一句話解釋解決的問題關鍵點
表、行、列資料的組織方式如何儲存結構化資料表 = Excel 工作表,行 = 記錄,列 = 欄位
主鍵每行的唯一識別如何精確找到一行資料唯一、非空、不變
外鍵連接表的橋樑如何關聯不同表的資料指向另一張表的主鍵
SQL和資料庫對話的語言如何增刪改查資料SELECT、INSERT、UPDATE、DELETE
索引加速查詢的資料結構如何快速找到資料B+ 樹,減少磁碟 I/O
事務保證資料安全的機制如何防止併發衝突和遺失資料ACID:原子性、一致性、隔離性、持久性

寫在最後

資料庫是一個博大精深的主題,本文只是入門。如果你想繼續深入學習,建議按以下路線:

下一步學習

  1. 動手實踐:安裝 MySQL 或 PostgreSQL,建立表、插入資料、寫 SQL 查詢
  2. ORM 框架:學習如何在程式碼中使用資料庫(如 SQLAlchemy、Prisma、TypeORM)
  3. 索引最佳化:深入研究複合索引、覆蓋索引、索引下推等進階主題
  4. 事務原理:了解 MVCC(多版本併發控制)、鎖機制、隔離級別實作
  5. 分散式資料庫:學習分庫分表、讀寫分離、主從複製等架構

記住:理論 + 實踐 = 真正的掌握