實測單表近 4 億行資料 (393,625,073 行) 的查詢與寫入效能,揭示大表效能的核心決定因素:業務操作集中在熱點資料 + 索引分區檔案不需 IO 切換。
mysql> SELECT COUNT(1) FROM account_log;
+-----------+
| count(1) |
+-----------+
| 393625073 | -- 3.9 億行
+-----------+
1 row in set (1 min 6.98 sec) -- 全表掃描耗時參考
| DAO 方法 | 業務場景 | 每分鐘請求數 | 平均延遲 | 網路延遲(阿里雲) |
|---|---|---|---|---|
| selectByOrderId | 主鍵/唯一索引點查 | 358 | 3 ms | 2-3 ms |
| insert | 單行寫入 | 100 | 2.89 ms | 2-3 ms |
-- 範圍分區表示例 (按月分區)
CREATE TABLE account_log (
id BIGINT NOT NULL AUTO_INCREMENT,
order_id VARCHAR(64) NOT NULL,
amount DECIMAL(18,2),
create_time DATETIME NOT NULL,
PRIMARY KEY (id, create_time) -- 分區鍵必須包含在主鍵中
) ENGINE=InnoDB
PARTITION BY RANGE (TO_DAYS(create_time)) (
PARTITION p202401 VALUES LESS THAN (TO_DAYS('2024-02-01')),
PARTITION p202402 VALUES LESS THAN (TO_DAYS('2024-03-01')),
PARTITION p202403 VALUES LESS THAN (TO_DAYS('2024-04-01')),
PARTITION p_future VALUES LESS THAN MAXVALUE
);
EXPLAIN PARTITIONS
SELECT * FROM account_log
WHERE create_time >= '2024-03-01' AND create_time < '2024-04-01'
AND order_id = 'ORD_12345';
-- partitions 欄位應只顯示 p202403
| 優化點 | 說明 | 效果 |
|---|---|---|
| 範圍分區 (時間/ID) | 物理隔離冷熱資料,查詢自動裁剪分區 | 掃描行數降低 90%+ |
| 主鍵設計 | 自增 BIGINT + 分區鍵組合主鍵 | 避免主鍵碎片、支援分區 |
| 索引最小化 | 僅建立高選擇性業務索引 | 減少寫入放大、節省空間 |
| Buffer Pool 適配 | 熱點索引+資料頁 < 70% Buffer Pool | 命中率 > 99% |
| 歸檔策略 | 定期 `DROP PARTITION` / `EXCHANGE PARTITION` | 釋放空間、維護效能 |
| 避免全表掃描 | 嚴禁無 WHERE / 無索引查詢 | 防止緩衝區污染 |
-- 分區統計
SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, TABLE_ROWS, DATA_LENGTH, INDEX_LENGTH
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_NAME = 'account_log'
ORDER BY PARTITION_ORDINAL_POSITION;
-- Buffer Pool 熱點頁面
SELECT * FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
WHERE TABLE_NAME = 'account_log'
ORDER BY PAGE_TYPE, INDEX_NAME;
單表資料量不是效能殺手,**訪問模式**才是。只要:
億級甚至十億級單表在 MySQL/InnoDB 上完全可控,核心在於冷熱分離的物理實現。