InnoDB和MyISAM是許多人在使用MySQL時最經常使用的兩個表類型,這兩個表類型各有優劣,視具體應用而定。基本的差異爲:MyISAM類型不支持事務處理等高級處理,而InnoDB類型支持。MyISAM類型的表強調的是性能,其執行數度比InnoDB類型更快,可是不提供事務支持,而InnoDB提供事務支持已經外部鍵等高級數據庫功能。 如下是一些細節和具體實現的差異:html
緣由以下: 一、首先我目前平臺上承載的大部分項目是讀多寫少的項目,而MyISAM的讀性能是比Innodb強很多的。 二、MyISAM的索引和數據是分開的,而且索引是有壓縮的,內存使用率就對應提升了很多。能加載更多索引,而Innodb是索引和數據是緊密捆綁的,沒有使用壓縮從而會形成Innodb比MyISAM體積龐大不小。 三、從平臺角度來講,常常隔1,2個月就會發生應用開發人員不當心update一個表where寫的範圍不對,致使這個表無法正經常使用了,這個時候MyISAM的優越性就體現出來了,隨便從當天拷貝的壓縮包取出對應表的文件,隨便放到一個數據庫目錄下,而後dump成sql再導回到主庫,並把對應的binlog補上。若是是Innodb,恐怕不可能有這麼快速度,別和我說讓Innodb按期用導出xxx.sql機制備份,由於我平臺上最小的一個數據庫實例的數據量基本都是幾十G大小。 四、從我接觸的應用邏輯來講,select count() 和order by 是最頻繁的,大概能佔了整個sql總語句的60%以上的操做,而這種操做Innodb其實也是會鎖表的,不少人覺得Innodb是行級鎖,那個只是where對它主鍵是有效,非主鍵的都會鎖全表的。 五、還有就是常常有不少應用部門須要我給他們按期某些表的數據,MyISAM的話很方便,只要發給他們對應那表的frm.MYD,MYI的文件,讓他們本身在對應版本的數據庫啓動就行,而Innodb就須要導出xxx.sql了,由於光給別人文件,受字典數據文件的影響,對方是沒法使用的。 六、若是和MyISAM比insert寫操做的話,Innodb還達不到MyISAM的寫性能,若是是針對基於索引的update操做,雖然MyISAM可能會遜色Innodb,可是那麼高併發的寫,從庫可否追的上也是一個問題,還不如經過多實例分庫分表架構來解決。 七、若是是用MyISAM的話,merge引擎能夠大大加快應用部門的開發速度,他們只要對這個merge表作一些select count()操做,很是適合大項目總量約幾億的rows某一類型(如日誌,調查統計)的業務表。 固然Innodb也不是絕對不用,用事務的項目如模擬炒股項目,我就是用Innodb的,活躍用戶20多萬時候,也是很輕鬆應付了,所以我我的也是很喜歡Innodb的,只是若是從數據庫平臺應用出發,我仍是會首選MyISAM。 另外,可能有人會說你MyISAM沒法抗太多寫操做,可是我能夠經過架構來彌補,說個我現有用的數據庫平臺容量:主從數據總量在幾百T以上,天天十多億 pv的動態頁面,還有幾個大項目是經過數據接口方式調用未算進pv總數,(其中包括一個大項目由於初期memcached沒部署,致使單臺數據庫天天處理 9千萬的查詢)。而個人總體數據庫服務器平均負載都在0.5-1左右。java
MyISAMmysql
InnoDB
複製代碼
構成上的區別:算法
每一個MyISAM在磁盤上存儲成三個文件。第一個文件的名字以表的名字開始,擴展名指出文件類型。
複製代碼
.frm文件存儲表定義。sql
數據文件的擴展名爲.MYD (MYData)。數據庫
索引文件的擴展名是.MYI (MYIndex)。緩存
基於磁盤的資源是InnoDB表空間數據文件和它的日誌文件,InnoDB 表的大小隻受限於操做系統文件的大小,通常爲 2GB
複製代碼
事務處理上方面:安全
MyISAM類型的表強調的是性能,其執行數度比InnoDB類型更快,可是不提供事務支持
InnoDB提供事務支持事務,外部鍵等高級數據庫功能
複製代碼
SELECT UPDATE,INSERT,Delete操做 若是執行大量的SELECT,MyISAM是更好的選擇服務器
1.若是你的數據執行大量的INSERT或UPDATE,出於性能方面的考慮,應該使用InnoDB表
複製代碼
2.DELETE FROM table時,InnoDB不會從新創建表,而是一行一行的刪除。架構
3.LOAD TABLE FROM MASTER操做對InnoDB是不起做用的,解決方法是首先把InnoDB表改爲MyISAM表,導入數據後再改爲InnoDB表,可是對於使用的額外的InnoDB特性(例如外鍵)的表不適用
對AUTO_INCREMENT的操做
每表一個AUTO_INCREMEN列的內部處理。
複製代碼
MyISAM爲INSERT和UPDATE操做自動更新這一列。這使得AUTO_INCREMENT列更快(至少10%)。在序列頂的值被刪除以後就不能再利用。(當AUTO_INCREMENT列被定義爲多列索引的最後一列,能夠出現重使用從序列頂部刪除的值的狀況)。
AUTO_INCREMENT值可用ALTER TABLE或myisamch來重置
對於AUTO_INCREMENT類型的字段,InnoDB中必須包含只有該字段的索引,可是在MyISAM表中,能夠和其餘字段一塊兒創建聯合索引
更好和更快的auto_increment處理
若是你爲一個表指定AUTO_INCREMENT列,在數據詞典裏的InnoDB表句柄包含一個名爲自動增加計數器的計數器,它被用在爲該列賦新值。
複製代碼
自動增加計數器僅被存儲在主內存中,而不是存在磁盤上
關於該計算器的算法實現,請參考
AUTO_INCREMENT列在InnoDB裏如何工做
表的具體行數 select count() from table,MyISAM只要簡單的讀出保存好的行數,注意的是,當count()語句包含 where條件時,兩種表的操做是同樣的
InnoDB 中不保存表的具體行數,也就是說,執行select count(*) from table時,InnoDB要掃描一遍整個表來計算有多少行
複製代碼
鎖 表鎖
提供行鎖(locking on row level),提供與 Oracle 類型一致的不加鎖讀取(non-locking read in
複製代碼
InnoDB 和 MyISAM,是在使用MySQL最經常使用的兩個表類型,各有優缺點,視具體應用而定。下面是已知的二者之間的差異,僅供參考。
InnoDB InnoDB 給 MySQL 提供了具備事務(commit)、回滾(rollback)和崩潰修復能力(crash recovery capabilities)的事務安全(transaction-safe (ACID compliant))型表。 InnoDB 提供了行鎖(locking on row level),提供與 Oracle 類型一致的不加鎖讀取(non-locking read in SELECTs)。這些特性均提升了多用戶併發操做的性能表現。在InnoDB表中不須要擴大鎖定(lock escalation),由於InnoDB 的列鎖定(row level locks)適宜很是小的空間。InnoDB 是 MySQL 上第一個提供外鍵約束(FOREIGNKEY constraints)的表引擎。 InnoDB 的設計目標是處理大容量數據庫系統,它的 CPU 利用率是其它基於磁盤的關係數據庫引擎所不能比的。在技術上,InnoDB 是一套放在 MySQL 後臺的完整數據庫系統,InnoDB 在主內存中創建其專用的緩衝池用於高速緩衝數據和索引。 InnoDB 把數據和索引存放在表空間裏,可能包含多個文件,這與其它的不同,舉例來講,在 MyISAM 中,表被存放在單獨的文件中。InnoDB 表的大小隻受限於操做系統的文件大小,通常爲 2 GB。 在 http://www.innodb.com/ 上能夠找到 InnoDB 最新的信息。InnoDB 手冊的最新版本老是被放置在那裏,而且在那裏能夠獲得 InnoDB 的商業許可(order commercial licenses)以及支持。 InnoDB 如今(2001年十月)在一些大的需高性能的數據庫站點上被使用。著名的 Internet 新聞站點 Slashdot.org就是使用的 InnoDB。 Mytrix, Inc. 在 InnoDB 表上存儲了超過 1 TB 的數據,並且另外的一個站點在 InnoDB 表上處理着平均每秒 800 次的插入/更新的負載。
MySQL InnoDB 的性能問題討論
MySQL最爲人垢病的缺點就是缺少事務的支持,MyISAM 性能雖然出衆,不是沒有代價的,InnoDB 又如何呢?InnoDB 的磁盤性能很使人擔憂,MySQL 缺少良好的 tablespace 真是天大的缺陷!
InnoDB的表空間分紅三種,一種是裸設備,一種是若干個 ibdata 文件(缺省方式),再一種是 Per-Table 文件,第一種用得少,第二種顯然比第三種效率更差,本文的討論基於 Per-Table,也即 innodb_file_per_table 配置參數。
現象重現:導出一個幾百萬行數據、帶若干索引、有過頻繁更新的表出來再導入,若是能以真實環境下的表來作測試就更理想,到 data 目錄下觀察對應的數據文件的 size 增加狀況,會發現前 1G 速度至關使人滿意,但是越日後效率越低,到後面基本就是蝸牛般的速度了。
不是隻有導入纔會讓你慢得受不了,alter column/index 都會這樣。。。
InnoDB 跟磁盤相關的文件存儲,能夠分紅兩個部分,一個是日誌文件,另外一個是數據文件。當有頻繁的 INSERT/UPDATE 操做的時候,InnoDB 須要分別寫入這兩個文件,日誌文件是順序操做,數據文件包括了表數據和索引數據兩個部分(和 MyISAM 直接拆開成表文件和索引文件不一樣,InnoDB 的表和索引是在同一個文件當中的)。
InnoDB 的索引用的是 BTREE 格式,若是當前更新的記錄影響到索引的變化,邏輯上就存在三個操做,從原來的 BTREE 找到並摘除原來這行的記錄並作調整、插入行數據、根據新數據查找 BTREE 相應的位置並從新插入新索引信息,假設索引數爲 N,相應的邏輯操做數就爲 1 + 2N,顯然這些信息不能保證在同一個磁盤連續空間上,所以須要 1 + 2N 次的磁頭移動,行數越大、文件尺寸越大,磁頭的移動幅度也就可能越大,帶來的後果顯然是極差的磁盤 IO 效率。
MySQL 對於 MyISAM 的的磁盤 IO 優化是如何建議的呢?使用符號連接將表文件和索引文件分別指向不一樣的不一樣的目錄,分散到不一樣的磁盤上以增長系統的訪問速度。這種優化方式,在 InnoDB 上徹底沒有可能性!
若是有 tablespace 支持,磁盤效率問題就好解決了,一如商業數據庫的作法,將日誌、表文件、索引文件分別分佈到不一樣的表空間也就是物理磁盤上,但是 MySQL 一直到 5.1 都沒有提供 tablespace 功能,僅在 NDB/NDBCLUSTER 中才提供,可是 -- "CREATE TABLESPACE was added in MySQL 5.1.6. In MySQL 5.1, it is useful only with Disk Data storage for MySQL Cluster."。
不知道 Yahoo 等大網站是怎麼解決這個難題的。。。頭痛。。。考慮切換到 PostgreSQL 中。。。
MySQL提供了數據庫的同步功能,這對咱們實現數據庫的冗災、備份、恢復、負載均衡等都是有極大幫助的。本文描述了常見的同步設置方法。 1、準備服務器 因爲MySQL不一樣版本之間的(二進制日誌)binlog格式可能會不同,所以最好的搭配組合是Master的MySQL版本和Slave的版本相同或者更低,Master的版本確定不能高於Slave版本。 本文中,咱們假設主服務器(如下簡稱Master)和從服務器(如下簡稱Slave)的版本都是5.0.15,操做系統是Linux Ubuntu 5.0.x。 假設同步Master的主機名爲:rep1,Slave主機名爲:rep2,2個MySQL的basedir目錄都是/usr/local/mysql,datadir都是:/usr/local/MySQL/data。 2、設置同步服務器 一、設置同步Master 每一個同步服務器都必須設定一個惟一的編號,不然同步就不能正常運行了。接下來開始修改 my.cnf,增長如下幾行: server-id = 1 log-bin set-variable=binlog-ignore-db=MySQL 而後在Master上增長一個帳號專門用於同步,以下: MySQL>GRANT REPLICATION SLAVE ON . TO rep@rep2 IDENTIFIED BY 'rep'; 若是想要在Slave上有權限執行 "LOAD TABLE FROM MASTER" 或 "LOAD DATA FROM MASTER" 語句的話,必須授予全局的 FILE 和 SELECT 權限: MySQL>GRANT FILE,SELECT,REPLICATION SLAVE ON . TO rep@rep2 IDENTIFIED BY 'rep'; 第三行表示不記錄數據庫MySQL的更新日誌,這就避免了Master上的權限設置等被同步到Slave上,若是對這方面沒有限制,就能夠不設置這個參數。 接下來備份Master上的數據,首先執行以下SQL語句: MySQL>FLUSH TABLES WITH READ LOCK; 不要退出這個終端,不然這個鎖就不生效了;接着導出數據,能夠直接打包壓縮數據文件,也可使用MySQLdump工具來作,推薦前者的方法,這樣更爲快捷簡便。 root$cd /usr/local/MySQL root$tar zcf data.tar.gz ./data (在這裏也多是 "var" 等其它實際存放數據文件的目錄,根據實情而定) 而後將這些數據拷貝到Slave服務器上,解開,設置好正確的權限及屬主等;以後,執行 "UNLOCK TABLES" 語句來釋放鎖。 二、設置Slave 修改my.cnf,增長以下幾行: server-id = 2 master-host = rep1 #主服務器名 master-user = rep #同步帳戶名,默認是test master-password = rep #同步賬戶密碼,默認是空 master-port = 3306 #主服務器的 TCP/IP 端口號,默認是3306 set-variable=replicate-ignore-db=MySQL #略過同步的數據庫名,若是有多個,請設置屢次 set-variable=replicate-do-db=yejr #想要同步的數據庫名,若是有多個,請設置屢次 接下來在Slave上檢驗一下是否能正確鏈接到Master上,而且具有相應的權限。 root$MySQL -hrep1 -urep -prep MySQL>SHOW GRANTS; +---------------------------------------------------------------------------------------------------------------------+ | Grants for rep@rep2 | +---------------------------------------------------------------------------------------------------------------------+ | GRANT SELECT, FILE, REPLICATION SLAVE ON . TO 'rep'@'rep2' IDENTIFIED BY PASSWORD '*9FF2C222F44C7BBA5CC7E3BE8573AA4E1776278C' | +---------------------------------------------------------------------------------------------------------------------+ 如今,能夠啓動Slave了。啓動成功後,登陸Slave,查看一下同步狀態: MySQL -hlocalhost -uroot MySQL>SHOW SLAVE STATUS/G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: rep1 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: binlog.000001 Read_Master_Log_Pos: 98 Relay_Log_File: relay.000003 Relay_Log_Pos: 232 Relay_Master_Log_File: binlog.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 98 Relay_Log_Space: 232 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 1 row in set (0.00 sec) 能夠看到,Slave_IO_Running 和 Slave_SQL_Running 兩列的值都爲 "Yes",這代表 Slave 的 I/O 和 SQL 線程都在正常運行。
MySQL服務器安裝完以後如何調節性能 key_buffer_size - 這對MyISAM表來講很是重要。若是隻是使用MyISAM表,能夠把它設置爲可用內存的 30-40%。合理的值取決於索引大小、數據量以及負載 -- 記住,MyISAM表會使用操做系統的緩存來緩存數據,所以須要留出部份內存給它們,不少狀況下數據比索引大多了。儘管如此,須要老是檢查是否全部的 key_buffer 都被利用了 -- .MYI 文件只有 1GB,而 key_buffer 卻設置爲 4GB 的狀況是很是少的。這麼作太浪費了。若是你不多使用MyISAM表,那麼也保留低於 16-32MB 的 key_buffer_size 以適應給予磁盤的臨時表索引所需。
innodb_buffer_pool_size - 這對Innodb表來講很是重要。Innodb相比MyISAM表對緩衝更爲敏感。MyISAM能夠在默認的 key_buffer_size 設置下運行的能夠,然而Innodb在默認的 innodb_buffer_pool_size 設置下卻跟蝸牛似的。因爲Innodb把數據和索引都緩存起來,無需留給操做系統太多的內存,所以若是隻須要用Innodb的話則能夠設置它高達 70-80% 的可用內存。一些應用於 key_buffer 的規則有 -- 若是你的數據量不大,而且不會暴增,那麼無需把 innodb_buffer_pool_size 設置的太大了。
innodb_additional_pool_size - 這個選項對性能影響並不太多,至少在有差很少足夠內存可分配的操做系統上是這樣。不過若是你仍然想設置爲 20MB(或者更大),所以就須要看一下Innodb其餘須要分配的內存有多少。
innodb_log_file_size 在高寫入負載尤爲是大數據集的狀況下很重要。這個值越大則性能相對越高,可是要注意到可能會增長恢復時間。我常常設置爲 64-512MB,跟據服務器大小而異。
innodb_log_buffer_size 默認的設置在中等強度寫入負載以及較短事務的狀況下,服務器性能還能夠。若是存在更新操做峯值或者負載較大,就應該考慮加大它的值了。若是它的值設置過高了,可能會浪費內存 -- 它每秒都會刷新一次,所以無需設置超過1秒所需的內存空間。一般 8-16MB 就足夠了。越小的系統它的值越小。
innodb_flush_logs_at_trx_commit 是否爲Innodb比MyISAM慢1000倍而頭大?看來也許你忘了修改這個參數了。默認值是 1,這意味着每次提交的更新事務(或者每一個事務以外的語句)都會刷新到磁盤中,而這至關耗費資源,尤爲是沒有電池備用緩存時。不少應用程序,尤爲是從 MyISAM轉變過來的那些,把它的值設置爲 2 就能夠了,也就是不把日誌刷新到磁盤上,而只刷新到操做系統的緩存上。日誌仍然會每秒刷新到磁盤中去,所以一般不會丟失每秒1-2次更新的消耗。若是設置爲 0 就快不少了,不過也相對不安全了 -- MySQL服務器崩潰時就會丟失一些事務。設置爲 2 指揮丟失刷新到操做系統緩存的那部分事務。
table_cache -- 打開一個表的開銷可能很大。例如MyISAM把MYI文件頭標誌該表正在使用中。你確定不但願這種操做太頻繁,因此一般要加大緩存數量,使得足以最大限度地緩存打開的表。它須要用到操做系統的資源以及內存,對當前的硬件配置來講固然不是什麼問題了。若是你有200多個表的話,那麼設置爲 1024 也許比較合適(每一個線程都須要打開表),若是鏈接數比較大那麼就加大它的值。我曾經見過設置爲 100,000 的狀況。
thread_cache -- 線程的建立和銷燬的開銷可能很大,由於每一個線程的鏈接/斷開都須要。我一般至少設置爲 16。若是應用程序中有大量的跳躍併發鏈接而且 Threads_Created 的值也比較大,那麼我就會加大它的值。它的目的是在一般的操做中無需建立新線程。
query_cache -- 若是你的應用程序有大量讀,並且沒有應用程序級別的緩存,那麼這頗有用。不要把它設置太大了,由於想要維護它也須要很多開銷,這會致使MySQL變慢。一般設置爲 32-512Mb。設置完以後最好是跟蹤一段時間,查看是否運行良好。在必定的負載壓力下,若是緩存命中率過低了,就啓用它。
注意:就像你看到的上面這些全局表量,它們都是依據硬件配置以及不一樣的存儲引擎而不一樣,可是會話變量一般是根據不一樣的負載來設定的。若是你只有一些簡單的查詢,那麼就無需增長 sort_buffer_size 的值了,儘管你有 64GB 的內存。搞很差也許會下降性能。 我一般在分析系統負載後纔來設置會話變量。
查看引擎類型 通常狀況下,MySQL會默認提供多種存儲引擎,能夠經過下面的查看:
(1)看你的MySQL如今已提供什麼存儲引擎: mysql> show engines;
(2)看你的MySQL當前默認的存儲引擎: mysql> show variables like '%storage_engine%';
(3)你要看某個表用了什麼引擎(在顯示結果裏參數engine後面的就表示該表當前用的存儲引擎): mysql> show create table 表名;
(4) 查看引擎狀態: show engine innodb status;