members 表超過 1000 萬筆記錄,查詢嚴重緩慢。團隊採用「分表 + 線上 DDL」雙管齊下策略。
將單表拆分為 100 張同結構子表 members00 ~ members99,依 mid % 100 路由。
<?php
for ($i = 0; $i < 100; $i++) {
// 建表語句 (實際執行時取消註解)
// echo "CREATE TABLE db2.members" . sprintf("%02d", $i) . " LIKE db1.members;
";
// 資料遷移語句
echo "INSERT INTO members" . sprintf("%02d", $i)
. " SELECT * FROM members WHERE mid % 100 = $i;
";
}
?>
mid 為主鍵,Hash 分布均勻$table = 'members' . sprintf('%02d', $mid % 100)UNION ALL 合併結果,或引入中介層 (如 ShardingSphere)原表 8GB 含大量冗餘欄位,需重構結構。
CREATE TABLE members_tmp LIKE members;ALTER TABLE members_tmp ... (新增/刪除欄位、調整型別、建索引)INSERT INTO members_tmp SELECT * FROM members WHERE mid BETWEEN ? AND ?,每批 5 萬筆RENAME TABLE members TO members_bak, members_tmp TO members;/* 經典無鎖切換語句 */ RENAME TABLE members TO members_bak, members_tmp TO members;
SLEEP(0.01) 降低主庫壓力Seconds_Behind_Master 確保從庫同步無延遲phpMyAdmin 顯示 12.34,但 WHERE price = 12.34 查無結果。
-- 原因:FLOAT 存儲為近似值 SELECT * FROM products WHERE price = 12.34; -- 失敗 SELECT * FROM products WHERE ABS(price - 12.34) < 0.001; -- 正確
建議: 金額/精度敏感欄位務必使用 DECIMAL(10,2)。
| 優化手段 | 適用場景 | 複雜度 | 風險 |
|---|---|---|---|
| Hash 分表 | 單表 > 500萬行、高並發寫入 | 高 (需改應用) | 跨分表查詢複雜 |
| 影子表 + RENAME | 大表結構變更、索引重建 | 中 | 極低 (原子切換) |
| PT-OSC / GH-OST | 自動化線上 DDL 工具 | 低 (工具化) | 極低 |
現代架構推薦:分庫分表中介層 (ShardingSphere, Vitess) + 線上 DDL 工具 (gh-ost),將複雜度下沉基礎設施層。