中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何進行MySQL Memory 存儲引擎的淺析

發布時間:2021-12-20 15:10:50 來源:億速云 閱讀:134 作者:柒染 欄目:數據庫

本篇文章給大家分享的是有關如何進行MySQL Memory 存儲引擎的淺析,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

前言

需求源自項目中的MemCache需求,開始想用MemCached(官方站點: ),但這個在Linux下面應用廣泛的開源軟件無官方支持的Windows版本。后來看到博客園在用NorthScale Memcached Server(官方站點:),貌似共享收費,又猶豫了。其實項目里的需求很簡單,也想自己用.Net Cache來實現,但穩定性難以評估,開發維護成本又似乎太大,沒辦法,My SQL Memory Storage成了唯一選擇,因為幾乎不怎么需要編寫代碼。

官方文檔(譯自5.5版本的The Memory Storage Engine)

Memory存儲引擎將表的數據存放在內存中。Memory替代以前的Heap成為首選項,但同時向下兼容,Heap仍被支持。

Memory存儲引擎特性:

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存儲引擎官方:http://forums.mysql.com/list.?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();

www.2cto.com            DataTableInsertAndSelect();

        }

    }//end class

}

.Net Cache讀寫性能毫無疑問大大領先于引擎

InnoDB寫入耗時大概是MyIsam和Memory的5倍左右,它的行鎖機制必然決定了寫入時的更多性能開銷,而它的強項在于多線程的并發處理,而本測試未能體現其優勢。

三種數據庫引擎在SELECT性能上差不多,Memory稍占優,同樣高并發下的比較有待進一步測試

以上就是如何進行MySQL Memory 存儲引擎的淺析,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

郧西县| 长武县| 迭部县| 修武县| 焦作市| 海淀区| 城市| 青岛市| 苍山县| 怀柔区| 紫金县| 台东市| 潍坊市| 元谋县| 运城市| 宁安市| 黔江区| 射洪县| 乐都县| 玛多县| 高平市| 农安县| 抚顺县| 肥乡县| 右玉县| 阜康市| 金昌市| 清河县| 玛沁县| 浏阳市| 扬州市| 印江| 汶川县| 珠海市| 松原市| 孟村| 新密市| 元江| 安平县| 马关县| 兴和县|