首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 記憶體表(MEMORY/HEAP)建立、參數調優與避坑全攻略

     編輯:MySQL 資料庫相關知識

建立記憶體表語法

CREATE TABLE `tablename` (
  `columnName` VARCHAR(256) NOT NULL
) ENGINE=MEMORY 
  DEFAULT CHARSET=utf8mb4 
  MAX_ROWS=100000000;
關鍵點:`ENGINE=MEMORY`、`MAX_ROWS` 預估上限(優化器參考)、字符集建議 `utf8mb4`。

核心參數調優

1. `max_heap_table_size`(全域硬性上限)

# my.cnf
[mysqld]
max_heap_table_size = 2048M  # 2GB,依實際記憶體與業務量設定
  • 單位:bytes,動態可調 `SET GLOBAL max_heap_table_size = 2147483648;`
  • 記憶體表資料量超過此值,**自動轉換為 MyISAM 磁碟表**,效能驟降。
  • 建議設為預估最大表資料量的 1.2~1.5 倍。

2. `tmp_table_size`(臨時表上限,影響內部排序/JOIN)

tmp_table_size = 1024M  # 建議與 max_heap_table_size 一致
  • 內部隱式臨時表超過此值同樣落盤 MyISAM。
  • 兩者取 **min(max_heap_table_size, tmp_table_size)** 作為實際上限。

MEMORY 引擎特性與限制(必讀)

特性說明影響
全局可見所有連線共享同一張表資料極適合緩存、查找表、會話共享
不支援 TEXT/BLOB僅定長/變長字串、數值、日期長文本需外部存儲(檔案/物件存儲)
索引類型預設 HASH 索引(=、<=>),可指定 BTREE範圍查詢(<、>、BETWEEN、LIKE)需建 BTREE
不支援 AUTO_INCREMENT5.6+ 已支援,舊版需應用層生成 ID版本確認
索引欄位不可為 NULL必須 `NOT NULL`建表時強制 `NOT NULL DEFAULT ''`
重啟資料全失結構保留(`.frm` 在磁碟),資料清空啟動腳本需自動回填
複製表失去索引/主鍵`CREATE TABLE t2 ENGINE=MEMORY SELECT * FROM t1` 僅複製資料與結構需額外 `ALTER TABLE` 加回主鍵/索引

資料持久化策略(解決重啟丟失)

方案 A:應用層懶加載(推薦,簡單通用)

// 擬代碼
function getMemoryTableData() {
    $count = query("SELECT COUNT(*) FROM mem_table");
    if ($count == 0) {
        // 重新從源表載入
        execute("DELETE FROM mem_table");
        execute("INSERT INTO mem_table SELECT * FROM source_table WHERE ...");
    }
    return query("SELECT * FROM mem_table");
}

方案 B:MySQL 啟動初始化腳本(需系統權限)

# /etc/mysql/init_memory_tables.sql
DELETE FROM mem_table;
INSERT INTO mem_table SELECT * FROM source_table WHERE ...;

# my.cnf
[mysqld]
init_file = /etc/mysql/init_memory_tables.sql
注意:`init_file` 在啟動早期執行,若源表鎖定或尚未就緒會失敗,需加重試邏輯或改用 Systemd `ExecStartPost`。

方案 C:觸發器同步(寫入源表同步更新記憶體表)

CREATE TRIGGER tr_source_after_insert AFTER INSERT ON source_table
FOR EACH ROW BEGIN
    INSERT INTO mem_table (id, name) VALUES (NEW.id, NEW.name);
END;

CREATE TRIGGER tr_source_after_update AFTER UPDATE ON source_table
FOR EACH ROW BEGIN
    UPDATE mem_table SET name = NEW.name WHERE id = NEW.id;
END;

CREATE TRIGGER tr_source_after_delete AFTER DELETE ON source_table
FOR EACH ROW BEGIN
    DELETE FROM mem_table WHERE id = OLD.id;
END;
優點:強一致性。缺點:增加源表寫入延遲,DDL 變更需同步修改觸發器。

常用管理 SQL 片段

-- 1. 安全刪除重建
DROP TABLE IF EXISTS `mem_cache`;

-- 2. 從源表複製結構+資料建立記憶體表
CREATE TABLE `mem_cache` ENGINE=MEMORY SELECT * FROM `source_table`;

-- 3. 補回主鍵與索引(複製會丟失)
ALTER TABLE `mem_cache` ADD PRIMARY KEY (`id`);
ALTER TABLE `mem_cache` ADD INDEX `idx_name` (`name`);

-- 4. 指定 BTREE 索引支援範圍查詢
CREATE TABLE `mem_range` (
  `id` INT UNSIGNED NOT NULL,
  `score` INT NOT NULL,
  INDEX `idx_score` (`score`) USING BTREE
) ENGINE=MEMORY;

-- 5. 查看記憶體表大小
SELECT TABLE_NAME, 
       ROUND(DATA_LENGTH/1024/1024,2) AS data_mb,
       ROUND(INDEX_LENGTH/1024/1024,2) AS index_mb,
       TABLE_ROWS
FROM information_schema.TABLES 
WHERE ENGINE='MEMORY' AND TABLE_SCHEMA='your_db';

效能對比與適用場景

場景MEMORY 表InnoDB + Buffer PoolRedis
單機、中小資料集(<1GB)、極高 QPS 讀取✅ 最佳次之(有 MVCC/鎖開銷)需外部依賴
跨機器共享、持久化、複雜查詢❌ 不支援✅ 原生支援✅ 叢集模式
資料頻繁變更、需 ACID❌ 無事務/持久化✅ 完整 ACID⚠️ Lua 腳本/事務有限
全文搜尋、JSON、GIS❌ 不支援✅ 原生支援⚠️ 模組支援

避坑總結

  1. 容量規劃:`max_heap_table_size` + `tmp_table_size` 必須 ≥ 預估峰值資料量,否則靜默落盤 MyISAM,效能崩塌無報錯。
  2. 索引選型:範圍查詢、排序、GROUP BY **必須**顯式 `USING BTREE`,預設 HASH 僅支援等值查詢。
  3. 字符集:`utf8mb4` 下 `VARCHAR(255)` 佔 768 bytes,記憶體消耗放大 3 倍,評估容量時按實際字節計算。
  4. 重啟預案:生產環境**必須**有自動回填機制(啟動腳本/應用懶加載/觸發器),否則重啟後業務直接報空指標/404。
  5. 並發寫入:MEMORY 表鎖粒度為**表級鎖**,高併發寫入嚴重衝突,適合「寫入少、讀取多、資料可重建」場景。

總結

MySQL MEMORY 引擎是**單機高速讀取緩存**的利器,但受限於「無持久化、表級鎖、不支援 TEXT/BLOB/範圍查詢(預設 HASH)」。落地關鍵在於:容量參數預留充足、索引按查詢模式選 BTREE/HASH、重啟回填機制落地、嚴格限定適用場景。若需跨機器、持久化、複雜查詢,請直接上 Redis Cluster 或 InnoDB + 足夠 Buffer Pool。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved