程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> MySQL Memory 存儲引擎淺析

MySQL Memory 存儲引擎淺析

編輯:MySQL綜合教程

MySQL Memory 存儲引擎淺析。本站提示廣大學習愛好者:(MySQL Memory 存儲引擎淺析)文章只能為提供參考,不一定能成為您想要的結果。以下是MySQL Memory 存儲引擎淺析正文


後來看到博客園在用NorthScale Memcached Server(官方站點:http://www.couchbase.com/products-and-services/memcached),貌似同享免費,又遲疑了。其實項目裡的需求很簡略,也想本身用.Net Cache來完成,但穩固性難以評價,開辟保護本錢又仿佛太年夜,沒方法,My SQL Memory Storage成了獨一選擇,由於簡直不怎樣須要編寫代碼。

先看官方手冊,然後寫了個簡略的機能測試。由於官方最新的文檔都是英文版的,所以譯了5.5版本 MySQL Memory Storage章節。

官方文檔(譯自5.5版本的The Memory Storage Engine)
Memory存儲引擎將表的數據寄存在內存中。Memory替換之前的Heap成為首選項,但同時向下兼容,Heap仍被支撐。

Memory存儲引擎特征:
Storage limits RAM Transactions No Locking granularity Table MVCC No Geospatial data type support No Geospatial indexing support No B-tree indexes Yes Hash indexes Yes Full-text search indexes No Clustered indexes No Data caches N/A Index caches N/A Compressed data No Encrypted data Yes Cluster database support No Replication support Yes Foreign key support No Backup / point-in-time recoveryc Yes Query cache support Yes Update statistics for data dictionary Yes    Memory 與 MySQL Cluster的比擬

願望安排內存引擎的開辟者們會斟酌MySQL Cluster能否是更好的選擇,參考以下Memory引擎的應用場景及特色:

能像會話(Session)或緩存(Caching)一樣便利操作和治理。
充足施展內存引擎的特色:高速度,低延遲。
只讀或讀為主的拜訪形式(不合適頻仍寫)。
然則內存表的機能受制於單線程的履行效力和寫操作時的表鎖開支,這就限制了內存表高負載時的擴大性,特殊是混雜寫操作的並發處置。另外,內存表中的數據在辦事重視啟後會喪失。

MySQL Cluster(集群)支撐與Memory引擎異樣的功效而且供給更高的機能,同時具有Memory不支撐的更多其它功效:

行鎖機制更好的支撐多線程多用戶並發。
更好的支撐讀寫混雜語句和擴大。
可選擇磁盤存儲介質永遠保留數據。
Shared-nothing和散布式架構包管無單點毛病,99.999% 可用性。
數據主動散布在各個節點,運用開辟者無需斟酌分區或分片處理計劃。
支撐MEMORY中不支撐的變長數據類型(包含BLOB 和 TEXT)。
關於MySQL集群與Memory引擎更多細節方面的比擬,可以檢查Scaling Web Services with MySQL Cluster: An Alternative to the MySQL Memory Storage Engine,該白皮書包含了這兩種技巧的機能研討,並一步步指點你若何將Memory用戶遷徙到MySQL集群。

每一個Memory表和一個磁盤文件聯系關系起來。文件名由表的名字開端,而且由一個.frm的擴大名來指明它存儲的表界說。要明白指出你想要一個Memory表,可以使用ENGINE選項來指定:

CREATE TABLE t (i INT) ENGINE = MEMORY;
如它們名字所指明的,Memory表被存儲在內存中,且默許應用哈希索引。這使得它們異常快,而且對創立暫時表異常有效。可是,當辦事器封閉之時,一切存儲在Memory內外的數據被喪失。由於表的界說被存在磁盤上的.frm文件中,所以表本身持續存在,在辦事重視啟動時它們是空的。

這個例子顯示你若何可以創立,應用並刪除一個Memory表:

CREATE TABLE test ENGINE=MEMORY;
SELECT ip,SUM(downloads) AS down FROM log_table GROUP BY ip;
SELECT COUNT(ip),AVG(down) FROM test;
DROP TABLE test;

MEMORY表有以下特點:

給Memory表的空間被以小塊來分派。表對拔出應用100%靜態哈希來。不須要溢出區或額定鍵空間。自在列表無額定的空間需求。已刪除的行被放在一個以鏈接的列內外,而且在你往內外拔出新數據之時被從新應用。Memory表也沒有平日與在哈希表中刪除加拔出相干的成績。
MEMORY表可以有多達每一個表64個索引,每一個索引16列,和3072字節的最年夜鍵長度。
MEMORY存儲引擎支撐HASH和BTREE索引。你可以經由過程添加一個以下所示的USING子句為給定的索引指定一個或另外一個:

CREATE TABLE lookup
(id INT, INDEX USING HASH (id))
ENGINE = MEMORY;
CREATE TABLE lookup
(id INT, INDEX USING BTREE (id))
ENGINE = MEMORY;

假如一個MEMORY 表的哈希索引鍵高度反復 (很多索引條目包括雷同的值),與索引鍵相干的更新和一切的刪除將會顯著變慢。 反復度與速度成反比,此時你可使用BTREE 索引來防止這個成績。
MEMORY表可以或許應用非獨一鍵。(對哈希索引的完成,這是一個不經常使用的功效)
對可包括NULL值的列的索引
MEMORY表應用固定的記載長度格局,像VARCHAR如許的可變長度類型將轉換為固定長度類型在MEMORY表中存儲。
MEMORY不克不及包括BLOB或TEXT列.
MEMORY支撐AUTO_INCREMENT列
MEMORY表支撐INSERT DELAYED
非暫時的MEMORY表在一切客戶端之間同享,就像其它任何非暫時表。
MEMORY表內容存儲在內存中,它會作為靜態查詢隊列創立外部暫時表的同享介質,然則兩個類型表的分歧在於MEMORY表不會碰到存儲轉換,而外部表則會:
1、MEMORY表不會轉換為磁盤表,而外部暫時表假如太年夜會主動轉換為磁盤表。
2、MEMORY表最年夜值受體系變量 max_heap_table_size 限制,默許為16MB,要轉變MEMORY表年夜小限制,須要轉變max_heap_table_size 的值。該值在 CREATE TABLE 時失效並隨同表的性命周期,(當你應用 ALTER TABLE 或 TRUNCATE TABLE敕令時,表的最年夜限制將轉變,或重啟MYSQL辦事時, 一切已存在的MEMORY表的最年夜限制將應用max_heap_table_size 的值重置。)
辦事器須要足夠內存來保持一切在統一時光應用的MEMORY表。
假如刪除行,內存表不會收受接管內存,只要整張表全體刪除的時刻,才停止內存收受接管。同時只要在統一張表中拔出新行時才會應用之前刪除行的內存空間。 要釋放已刪除行所占用的內存空間,可使用ALTER TABLE ENGINE=MEMORY對表停止強迫重建。當內容過時要釋放整張內存表,可以履行DELETE 或 TRUNCATE TABLE消除一切行,或許應用DROP TABLE刪除表。
當MySQL辦事器啟動時,假如你想填充MEMORY表,你可使用--init-file選項。例如,你可以把INSERT INTO ... SELECT 或LOAD DATA INFILE如許的語句放入這個文件中以便從耐久穩定的的數據源裝載表。
假如你正應用復制,當主辦事器被封閉且重啟動之時,主辦事器的MEMORY表變空。可是從辦事器認識不到這些表曾經變空,所以假如你從它們選擇數據,它就前往過時的內容。自從辦事器啟動後,當一個MEMORY表在主辦事器上第一次被應用之時,一個DELETE FROM語句被主動寫進主辦事器的二進制日記,是以再次讓從辦事器與主辦事器同步。留意,即便應用這個戰略,在主辦事器的重啟和它第一次應用該表之間的距離中,從辦事器仍然在表中有過時數據。可是,假如你應用--init-file選項於主辦事器啟動之時在其上履行MEMORY表。它確保這個時光距離為零。
在MEMORY表中,一行須要的內存應用以下公式盤算:

SUM_OVER_ALL_BTREE_KEYS(max_length_of_key + sizeof(char*) * 4)
+ SUM_OVER_ALL_HASH_KEYS(sizeof(char*) * 2)
+ ALIGN(length_of_row+1, sizeof(char*))

ALIGN()代表round-up因子,它使得行的長度為char指針年夜小切實其實切倍數。sizeof(char*)在32位機械上是4,在64位機械上是8。
如前所述,體系變量 max_heap_table_size 用於設置內存表的年夜小下限。要掌握單個表的最年夜值,須要在創立表之前設置會話變量。(不要設置全局max_heap_table_size 的值,除非你盤算一切客戶端創立的內存表都應用這個值)
上面的例子創立了兩張內存表,它們的年夜小限制分離為 1MB 和 2MB:

SET max_heap_table_size = 1024*1024;
/* Query OK, 0 rows affected (0.00 sec) */

CREATE TABLE t1 (id INT, UNIQUE(id)) ENGINE = MEMORY;
/* Query OK, 0 rows affected (0.01 sec) */

SET max_heap_table_size = 1024*1024*2;
/* Query OK, 0 rows affected (0.00 sec) */

CREATE TABLE t2 (id INT, UNIQUE(id)) ENGINE = MEMORY;
/* Query OK, 0 rows affected (0.00 sec) */

假如辦事重啟,兩張表的年夜小限制會應用全局的max_heap_table_size值回復復興。
你也能夠經由過程CREATE TABLE 的MAX_ROWS選項設置表的最年夜行數,但max_heap_table_size的優先級高於MAX_ROWS,當二者同時存在時為了最年夜兼容,你須要將max_heap_table_size設置一個公道值。

Memory存儲引擎官方服裝論壇t.vhao.net: http://forums.mysql.com/list.php?92

機能測試

分離測試比擬了MySQL的InnoDB、MyIsam、Memory三種引擎與.Net DataTable的Insert和Select機能(柱狀圖表現了其消費時光,單元百納秒,innodb_flush_log_at_trx_commit參數設置裝備擺設為1,每次測試重啟了MySQL以免Query Cache),年夜至成果以下:

寫入10000筆記錄比擬。

讀取1000筆記錄比擬。

測試劇本:


/******************************************************
MYSQL STORAGE ENGINE TEST
http://wu-jian.cnblogs.com/
2011-11-29
******************************************************/
CREATE DATABASE IF NOT EXISTS test
CHARACTER SET 'utf8'
COLLATE 'utf8_general_ci';
USE test;
/******************************************************
1.INNODB
******************************************************/
DROP TABLE IF EXISTS test_innodb;
CREATE TABLE IF NOT EXISTS test_innodb (
id INT UNSIGNED AUTO_INCREMENT COMMENT 'PK',
obj CHAR(255) NOT NULL DEFAULT '' COMMENT 'OBJECT',
PRIMARY KEY (id)
) ENGINE=INNODB;
/******************************************************
2.MYISAM
******************************************************/
DROP TABLE IF EXISTS test_myisam;
CREATE TABLE IF NOT EXISTS test_myisam (
id INT UNSIGNED AUTO_INCREMENT COMMENT 'PK',
obj CHAR(255) NOT NULL DEFAULT '' COMMENT 'OBJECT',
PRIMARY KEY (id)
) ENGINE=MYISAM;
/******************************************************
1.MEMORY
******************************************************/
DROP TABLE IF EXISTS test_memory;
CREATE TABLE IF NOT EXISTS test_memory (
id INT UNSIGNED AUTO_INCREMENT COMMENT 'PK',
obj CHAR(255) NOT NULL DEFAULT '' COMMENT 'OBJECT',
PRIMARY KEY (id)
) ENGINE=MEMORY;

測試代碼:

using System;
using System.Data;
using MySql.Data.MySqlClient;
namespace MySqlEngineTest
{
class Program
{
const string OBJ = "The MEMORY storage engine creates tables with contents that are stored in memory. Formerly, these were known as HEAP tables. MEMORY is the preferred term, although HEAP remains supported for backward compatibility.";
const string SQL_CONN = "Data Source=127.0.0.1;Port=3308;User ID=root;Password=root;DataBase=test;Allow Zero Datetime=true;Charset=utf8;pooling=true;";
const int LOOP_TOTAL = 10000;
const int LOOP_BEGIN = 8000;
const int LOOP_END = 9000;
#region Database Functions
public static bool DB_InnoDBInsert(string obj)
{
string commandText = "INSERT INTO test_innodb (obj) VALUES (?obj)";
MySqlParameter[] parameters = {
new MySqlParameter("?obj", MySqlDbType.VarChar, 255)
};
parameters[0].Value = obj;
if (DBUtility.MySqlHelper.ExecuteNonQuery(SQL_CONN, CommandType.Text, commandText, parameters) > 0)
return true;
else
return false;
}
public static string DB_InnoDBSelect(int id)
{
string commandText = "SELECT obj FROM test_innodb WHERE id = ?id";
MySqlParameter[] parameters = {
new MySqlParameter("?id", MySqlDbType.Int32)
};
parameters[0].Value = id;
return DBUtility.MySqlHelper.ExecuteScalar(SQL_CONN, CommandType.Text, commandText, parameters).ToString();
}
public static bool DB_MyIsamInsert(string obj)
{
string commandText = "INSERT INTO test_myisam (obj) VALUES (?obj)";
MySqlParameter[] parameters = {
new MySqlParameter("?obj", MySqlDbType.VarChar, 255)
};
parameters[0].Value = obj;
if (DBUtility.MySqlHelper.ExecuteNonQuery(SQL_CONN, CommandType.Text, commandText, parameters) > 0)
return true;
else
return false;
}
public static string DB_MyIsamSelect(int id)
{
string commandText = "SELECT obj FROM test_myisam WHERE id = ?id";
MySqlParameter[] parameters = {
new MySqlParameter("?id", MySqlDbType.Int32)
};
parameters[0].Value = id;
return DBUtility.MySqlHelper.ExecuteScalar(SQL_CONN, CommandType.Text, commandText, parameters).ToString();
}
public static bool DB_MemoryInsert(string obj)
{
string commandText = "INSERT INTO test_memory (obj) VALUES (?obj)";
MySqlParameter[] parameters = {
new MySqlParameter("?obj", MySqlDbType.VarChar, 255)
};
parameters[0].Value = obj;
if (DBUtility.MySqlHelper.ExecuteNonQuery(SQL_CONN, CommandType.Text, commandText, parameters) > 0)
return true;
else
return false;
}
public static string DB_MemorySelect(int id)
{
string commandText = "SELECT obj FROM test_memory WHERE id = ?id";
MySqlParameter[] parameters = {
new MySqlParameter("?id", MySqlDbType.Int32)
};
parameters[0].Value = id;
return DBUtility.MySqlHelper.ExecuteScalar(SQL_CONN, CommandType.Text, commandText, parameters).ToString();
}
#endregion
#region Test Functions InnoDB
static void InnoDBInsert()
{
long begin = DateTime.Now.Ticks;
for (int i = 0; i < LOOP_TOTAL; i++)
{
DB_InnoDBInsert(OBJ);
}
Console.WriteLine("InnoDB Insert Result: {0}", DateTime.Now.Ticks - begin);
}
static void InnoDBSelect()
{
long begin = DateTime.Now.Ticks;
for (int i = LOOP_BEGIN; i < LOOP_END; i++)
{
DB_InnoDBSelect(i);
}
Console.WriteLine("InnoDB SELECT Result: {0}", DateTime.Now.Ticks - begin);
}
static void MyIsamInsert()
{
long begin = DateTime.Now.Ticks;
for (int i = 0; i < LOOP_TOTAL; i++)
{
DB_MyIsamInsert(OBJ);
}
Console.WriteLine("MyIsam Insert Result: {0}", DateTime.Now.Ticks - begin);
}
static void MyIsamSelect()
{
long begin = DateTime.Now.Ticks;
for (int i = LOOP_BEGIN; i < LOOP_END; i++)
{
DB_MyIsamSelect(i);
}
Console.WriteLine("MyIsam SELECT Result: {0}", DateTime.Now.Ticks - begin);
}
static void MemoryInsert()
{
long begin = DateTime.Now.Ticks;
for (int i = 0; i < LOOP_TOTAL; i++)
{
DB_MemoryInsert(OBJ);
}
Console.WriteLine("Memory Insert Result: {0}", DateTime.Now.Ticks - begin);
}
static void MemorySelect()
{
long begin = DateTime.Now.Ticks;
for (int i = LOOP_BEGIN; i < LOOP_END; i++)
{
DB_MemorySelect(i);
}
Console.WriteLine("Memory SELECT Result: {0}", DateTime.Now.Ticks - begin);
}
static void DataTableInsertAndSelect()
{
//Insert
DataTable dt = new DataTable();
dt.Columns.Add("id", Type.GetType("System.Int32"));
dt.Columns["id"].AutoIncrement = true;
dt.Columns.Add("obj", Type.GetType("System.String"));
DataRow dr = null;
long begin = DateTime.Now.Ticks;
for (int i = 0; i < LOOP_TOTAL; i++)
{
dr = null;
dr = dt.NewRow();
dr["obj"] = OBJ;
dt.Rows.Add(dr);
}
Console.WriteLine("DataTable Insert Result: {0}", DateTime.Now.Ticks - begin);
//Select
long begin1 = DateTime.Now.Ticks;
for (int i = LOOP_BEGIN; i < LOOP_END; i++)
{
dt.Select("id = " + i);
}
Console.WriteLine("DataTable Select Result: {0}", DateTime.Now.Ticks - begin1);
}
#endregion
static void Main(string[] args)
{
InnoDBInsert();
InnoDBSelect();
//restart mysql to avoid query cache
MyIsamInsert();
MyIsamSelect();
//restart mysql to avoid query cache
MemoryInsert();
MemorySelect();
DataTableInsertAndSelect();
}
}//end class
}

總結
.Net Cache讀寫機能毫無疑問年夜年夜搶先於數據庫引擎
InnoDB寫入耗時年夜概是MyIsam和Memory的5倍閣下,它的行鎖機制必定決議了寫入時的更多機能開支,而它的強項在於多線程的並發處置,而本測試未能表現其優勢。
三種數據庫引擎在SELECT機能上差不多,Memory稍占優,異樣高並發下的比擬有待進一步測試。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved