Mysql innodb performance optimization mysql
Mysql innodb存儲引擎的性能優化 linux
本文翻譯自http://www.mysqlperformanceblog.com/files/presentations/UC2007-Innodb-Performance-Optimization.pdf sql
這裏只是我對這個PDF文件進行了翻譯,因爲本人剛從事mysql DBA一職,因此不少東西本身並不能很好的翻譯出來,其中對於硬件部分翻譯的應該還行,可是關於數據庫方面的翻譯的很差,你們就看看吧,翻譯本文只是想更 清楚的瞭解mysql 優化上的一些基本原則,而國內對於這個沒有完整的資料。本文的做者Heikki Tuuri是InnoDB的創始人,在翻譯過程當中一樣得到了Peter Zaitsev的幫助,他是《High Performance MySQL》一書的做者。 數據庫
做者: Heikki Tuuri windows
Email: pz@mysqlperformanceblog.com 設計模式
譯者: Timo Seven 緩存
Email: greycd@gmail.com 安全
你們有什麼意見能夠給我郵件。 性能優化
1. 通用應用程序的設計是相當重要的 服務器
1.1. 設計你的schema,索引和查詢,以及選擇正確的存儲引擎是經常使用的優化手段。
1.2. 在有些狀況下存儲引擎的選擇會影響到schema和索引
1.3. 咱們這裏不會覆蓋到通常的schema設計方法,可是會主要聚焦到Innodb存儲引擎。
2. 每一個存儲引擎都是不一樣的
2.1. MySQl提供多種存儲引擎可供選擇
2.2. 它們每一個都有不一樣的設計和操做屬性。
2.3. 一個給某個存儲引擎寫的應用程序可能在其它存儲引擎下表現良好。
2.4. 每一個存儲引擎都有特定的優化方式,因此它們只對特定的設計模式有用。
2.5. 咱們覆蓋全部對於InnoDB存儲引擎的作何不作。
3. 使用事務
3.1. InnoDB默認就是使用事務,甚至你不知道如何使用。每句語句都將在本身的事務內(假設你運行「autocommit」模式set autocommit=1),在每句語句後面都會自動增長commit語句。
3.2. 把多條update語句包裝在同一個事務是更有效率的方式。(set autcommit=0;..comit;…commit;)。不能讓事務過長,這樣會形成死鎖和等待超時。
4. 不要使用鎖表(lock tables)
4.1. 鎖表(LOCK TABLES)是設計用來給那些表級鎖的存儲引擎。在行級鎖的存儲引擎中事務是更好的選擇。InnoDB的的鎖錶行爲在不一樣的mysql 版本是不一樣的,若是你從MySQL4.0或者更新的版本升級,那你依賴於innodb_table_locks這個選項會致使不少問題。
5. 主鍵簇
5.1. 主鍵是特殊的
5.1.1. 經過主鍵訪問數據比經過其它key訪問更快。不管是在內存仍是磁盤經過主鍵查找都是最快的。
5.1.2. 數據都由主鍵彙集的。連續的主鍵值很容易讓同一頁主鍵的數據進行排序同時首字查詢也會很是有效率。可用於把全部須要訪問數據集中在一塊兒。把用戶信息存儲在一塊兒可使用(user_id,message_id)做爲主鍵來保存全部用戶的信息在不少頁中。主鍵是一個替代索引對於任何字段。
6. 主鍵的開銷
6.1. 主鍵在隨機排序是開銷比較大的,也會致使表產生碎片(主鍵的插入通常都是根據升序進行的)
6.1.1. 若是能夠裝載數據都經過主鍵來進行排序的。
6.1.2. 有時候把主鍵設置成自動增加(auto_increment)是一個好主意
6.2. 若是你不指定,主鍵默認就是一個內在的彙集key。因此最好就定義一個而且使用它。
6.3. UPDATE PK開銷是很是大的
6.3.1. 行數據將會在索引中物理的從一個地方移動位置。
6.3.2. 一般這種須要在設計上進行避免。
7. 讓主鍵儘可能短
7.1. 由於其它索引都是經過主鍵來構建索引的。
7.1.1. 使主鍵成爲其它索引的一部分。
7.2. 長主鍵會讓你的索引變大和變慢
7.2.1. 你能夠把主鍵變成惟一KEY,同時給主鍵添加自動增加。你不能簡單的讓InnoDB本身去建立它的內部主鍵,經過把主鍵變爲惟一key由於MySQL會自動的轉換一個非空的的惟一key做爲主鍵。
7.2.2. 若是一個表中只有主鍵,同時全部查詢都是經過主鍵進行,即便主鍵是比較長的,那經過主鍵進行查詢也是更快的。
8. InnoDB的索引
8.1. 讓惟一索引變的簡單
8.1.1. 不使用」insert buffer」會加快索引的更新。
8.2. 索引是不能作前綴壓縮的
8.2.1. 因此它會比MyISAM引擎佔用更多的空間
8.2.2. 要儘可能避免過多的索引
8.3. 對全部須要更新的列進行索引
8.3.1. 否則你將看到不肯看到的lock問題。 DELETE FROM users WHERE name=’peter’, 若是沒有對name列進行索引的話就會鎖住表中全部的行。
9. 自動增長將限制可擴展性
9.1. 自動增加的插入可能會用到表級鎖(但只會在insert語句的最後部分,沒有事務的狀況下)。即便你指定了自動增加列的值。
9.2. 對於併發插入將限制可可擴展性。
9.3. 會致使在運行中出現困難。
9.4. 致使超出MySQL所能分配的值。要特別當心那種很是長和隨機的主鍵。
10. 多版本
10.1. 只對須要的行進行lock將會得到更好的併發性能。
10.2. 普通的SELECT不會進行lock操做,只會去讀適當的行。
10.2.1. Lock在共享模式下,UPDATE作更新操做時會對讀進行Lock。
10.3. 甚至長時間的select查詢不會阻止對於表的update或者select操做。
10.4. 過分的慢查詢(一般在事務內)對於性能是很差的,如致使版本的不一致性。READ COMMITTED可以減輕這種問題。
10.4.1. InnoDB只能隔離一個行版本當讀取這行的時候沒有事務在運行。
11. 在共享模式下的…FOR UPDATE and LOCK
11.1. 在read commited模式下會進行select lock。由於不能不能lock一個不存在的行。因此這個跟普通的select是不一樣的。
11.2. SELECT…FOR UPDATE老是不得不訪問行數據頁進行lock,因此不能進行對這些查詢進行索引,就會減慢查詢的速度。
12. 減小死鎖
12.1. 在事務的數據庫中死鎖是廣泛存在的。
12.1.1. 在你InnoDB中沒有鎖的select語句是不會致使死鎖的。
12.1.2. 在你的應用須要控制好你的死鎖時間。
12.2. 若是可能的話確認在事務中鎖住的數據就是你請求的那些。
12.3. 讓update數據變小(分離你的事務)
12.4. 使用SELECT…FOR UPDATE若是你想更新大部分你所選擇的行。
12.5. 使用外部鎖能夠避免死鎖這個問題—應用程序級別的鎖,SELECT GET_LOCK(‘mylock’)等等。
13. 隔離級別是如何影響性能的
13.1. InnoDB支持不少種的隔離級別。這些隔離級別能夠設置爲全局有效也能夠針對每一個鏈接和每一個事務。
13.1.1. READ UMCOMMITED(不提交讀)—這個是不多使用。若是你不想有髒數據產生那就能夠很好的使用這個,可是會影響性能。
13.1.2. READ COMMITED(提角度)—全部提交事務的結果對於下一條語句都是顯而易見的。可能比其餘更高的隔離級別性能更高。容許老的內容更快的更新。在mysql5.1,InnoDB會有一些間歇鎖在這個級別上:使用行級複製和binlog能夠避免這個問題。
13.1.2.1. REPEATABLE READ(可重複讀)—默認的隔離級別。事務內的讀都是徹底可重複的,沒有幽靈行的產生。
13.1.2.2. SERIALIZABLE(串行化)– 讓全部select都鎖住select,儘量避免使用這個隔離級別。
14. 外鍵性能
14.1. 當更新行時候InnoDB都會檢查外鍵,並且不會進行批處理或者當事務提交時候檢查延遲。外鍵一般都有不少性能上的開銷,可是這也保證了數據庫的連續性。
14.2. 外鍵增長了不少行級鎖,這將會影響到不少其它表不光是本身直接更新的那張表。
14.3. 外鍵會鎖住子表,當父表在更新的時候。(select … for update在父表上這樣執行就不會鎖住子表)
15. 運行中的事務中的約束數量
15.1. 在必定數量內的運行中的事務和執行查詢,InnoDB性能表現良好
15.1.1. 多個運行中查詢可能致使互相之間干擾。Innodb_thread_concurrency可以被用做在InnoDB內核中限制線程數量。
15.1.2. 許多運行中事務會致使更多的鎖,同時形成機器負載增長。
15.1.3. 若是有可能,在同一時間內限制必定數量的查詢,在應用程序端作好隊列。
16. 注意不要有太多的表
16.1. InnoDB本身的表定義(字典)緩存依賴於MySQL的table_cache變量值。
16.2. 只要打開一次,InnoDB就不會從緩存中移除這個表。
16.3. 每張表大概要消耗4KB以上的空間。MySQL 5.1 的 InnoDB已經將這個空間減小了50% 到 75%
16.4. 當重啓時,每一個表的統計將會被從新計算。因此第一次操做會是很是耗資源的。MySQL的table_cache將會串行執行這些操做。
17. Insert…Select
17.1. Insert…Select語句執行時會對select進行鎖
17.2. 語句級別複製要求更新都是串行化的。在MysQL5.1 行級別更新在 READ COMMITED已經沒有問題了。
17.3. 不管何時你啓用或者不啓用log-bin,都須要保持一致性。
17.4. Innodb_locks_unsafe_for_binlog在MySQL5.0是有幫助的,可是你的複製有可能會被中斷,同時會禁止next-key的鎖。
17.5. SELECT…INTO OUTFILE + LOAD DATA INFILE常常被用做non-blocking的安全替代。
18. Next key lock(間隙鎖)
18.1. Innodb不光會鎖使用到行,也會鎖這些行之間的行(稱爲間隙行)。
18.2. 這個是爲了防止幽靈行的出現。 設置 「REPEATABLE READ」確實會讓InnoDB可重複的。
18.3. 對於MySQL語句級別的複製是頗有必要的。
18.4. 會讓一些寫負載大的機器上增長鎖的狀況。
18.5. 若是你沒有設置和使用二進制log(用做複製和恢復的),那能夠禁止這個間隙鎖。
18.6. 在MySQL5.1中,若是你使用行級複製就能夠安全的進行修改。
19. Count(*)的事實和傳說
19.1. InnoDB不能很好的控制count(*)的查詢–這個只是傳聞。在全部引擎中大部分count(*)查詢都用相同的方式進行查詢。 select count(*) from articles Where user_id=5
19.2. 在缺乏where字句的狀況下,InnoDB不對count(*)查詢進行優化–這個是事實。如select count(*) from users; InnoDB不能簡單存儲行的計數,每一個事務都有本身的表的視圖。由於有重要的工做還要去實現。你可使用觸發器和計數器。SHOW TABLE STATUS LIKE 」USERS」 能夠顯示錶近似的行數。
20. InnoDB和集體提交
20.1. 集體提交–提交多個事務經過單個日誌寫。這個能夠提升很是多的性能,特別是沒有作RAID的狀況下。
20.2. 在MySQL5.0下,集體提交不能在有二進制log的狀況下工做。因爲XA(分佈式事務)方法被實現,特別要當心從MysqL4.1進行的升級。
1. 一切都從內存開始
1.1. InnoDB_buffer_pool_size
1.1.1. 詳細指定了主要InnoDB緩存–數據和索引頁,插入緩存,鎖都會存在這裏。
1.1.2. 在大數據集的狀況下對於性能很是重要
1.1.3. 比OS級別的緩存更有效的多,特別對於寫操做。InnoDB不得不去繞過OS的buffer去寫。
1.1.4. 最好使用70%–80%的系統內存做爲InnoDB的buffer使用。
1.1.5. 默認值是8M,可用的獨立內存,要好好確認如何去配置。
1.2. InnoDB_additional_mem_pool
1.2.1. 僅僅存儲字典,它會自動增加,不用設置的太大。
2. InnoDB日誌
2.1. Innodb_log_file_size
2.1.1. 對於寫性能有很是重要的影響。要保持很是大。
2.1.2. 高的數值會增長你回覆的時間。檢查一下你能設置的最大的大小。
2.1.3. 最大的限制是4G。
2.2. Innodb_log_files_in_group
2.2.1. 這些文件指定了對於Log所能使用的大小。
2.2.2. 一般不須要改變其默認值。
3. InnoDB日誌
3.1. Innodb_log_buffer_size
3.1.1. 不要設置超過2-9M,除非你使用大量的超大文件,日誌文件都會被刷新在每秒執行完畢後。
3.1.2. 檢查innodb_os_log_written的增加來看你的日誌文件的寫入。
3.1.3. Innodb日誌是物理邏輯的,不是基於頁的,因此他們是很是緊湊的。
3.2. Innodb_flush_logs_at_trx_commit
3.2.1. 默認日誌被刷新到磁盤上在每次事務提交後。這個是爲了保證ACID(原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation,又稱獨立性)、持久性(Durability)),因此開銷很是大。
3.2.2. 能夠設置2和0,若是你能接受丟失最後一次的事務。
4. InnoDB日誌從新設置大小
4.1. 這個不是簡單修改選項和重啓下可以完成的。
4.2. 首先要關閉MysQL服務器
4.3. 確認它是正常關閉的(檢查有沒有錯誤日誌)
4.4. 移動全部InnoDB日誌文件到其它地方
4.5. 修改配置文件而後從新啓動MySQL服務器
4.6. 檢查錯誤日誌並查看是否產生新的日誌文件。
5. InnoDB_flush_method
5.1. 指定一個方法讓innodb跟OS文件系統一塊兒工做
5.2. Windows: 老是使用沒有buffer的IO方法
5.3. Unix:可使用fsync()或者O_SYNC/O_DSYNC進行刷新文件。
5.3.1. Fsync()一般是更快的,容許累計多個寫操做而後併發執行。
5.3.2. 一些操做系統容許關閉OS級別的緩衝針對InnoDB的數據文件。這樣很是好,你總不但願數據被緩衝2次吧。
5.4. Linux:O_DIRECT 使用直接的非緩衝IO。避免雙重緩衝,可能會讓寫更慢。
6. Innodb_file_per_table
6.1. InnoDB能夠存儲每一個表在單獨的文件中。
6.2. 對於系統須要的主表空間仍是須要的。
6.3. 可以幫助拆封不一樣的表到多個磁盤上。
6.4. 若是表被刪除容許回收空間。
6.5. 有時候使用連續的fsync()寫會更慢。
6.6. 當有大量的表的時候會增長啓動和關閉的時間。
7. 其它文件IO設定
7.1. Innodb_autoextend_increment–這個參數指定了對於共享表空間的增量(不是爲了單獨表空間的)。大的值能夠有效的減小碎片。
7.2. Innodb_file_io_thread–改變IO線程的數量,只對windows有效,全部4個線程能夠作不一樣的事情。
7.3. Innodb_open_file–這個值是用做指定每一個表空間所容許打開文件的數量。若是你有不少表那就要增長它。
7.4. Innodb_support_x–把這個值設置定爲0的時候可以減小innodb的工做在事務提交時。Binlog 可以經過異步的方式同步。
8. 最小化重啓時間
8.1. Innodb緩存池可能有一些未寫入到磁盤的數據。因此關閉的時候須要很是的時間。
8.2. 若是你想最小化關閉時間,那須要以下設定:
8.2.1. SET GLOBAL innodb_max_dirty_pages_pct=0
8.2.2. 執行show status後觀察 innodb_buffer_pool_pages_dirty
8.2.3. 當這個值變爲0的時候就能夠關閉服務器了
8.3. 在執行這個操做時候會讓性能下降,由於InnoDB將馬上要將髒數據頁寫入到磁盤上。
9. 排錯逃離清除
9.1. InnoDB不會經過delete來移除一行(和在更新時候舊的行),由於這些行可能會被其餘事務使用。
9.2. 清除線程被用在清除這些沒有用到的行。
9.3. 在一些工做負載,清除線程可能不能保持這些表空間無限的增加。經過show innodb status觀察transactions部分。
9.4. Innodb_max_purge_lag–這個是用來限制事務每次所能更新或者刪除最大的行數。將會延遲insert/update操做,因此清除線程會被保持。
9.5. 爲何咱們不用多個清除線程呢?
10. 併發控制設置
10.1. 設置能夠幫助InnoDB適應於控制大量的併發事務。
10.2. Innodb_thread_concurrency–InnoDB內核中同時能夠容許最大的在線程數量(0表示沒有限制),2*(CPU核數+磁盤數量)在理論上是一個合理的值,在實際應用中設置的更小一點可能會讓性能更好一點。
10.3. Innodb_commit_concurrency–容許同一時間內事務提交的最大線程數。
10.4. Innodb_concurrency_tickets–在不得不退出內核空間和等待以前能運行線程的數量。
10.5. Innodb_thread_sleep_delay
10.6. Innodb_sync_spin_loops
11. 得到高性能的不安全方式
11.1. Innodb有一些檢查和方法是數據不被最小化丟失和錯誤。
11.2. Innodb_doublewrite–這個值是用來保護部分頁的修改,只是禁止假如OS保證它不會發生。
11.3. Innodb_checksums–在頁中的數據校驗碼,幫助發現文件系統錯誤,內存損壞和其它問題。
11.3.1. 致使一部分大工做負載的機器會過載。
11.3.2. 當性能是第一的狀況下能夠禁止這個參數。
12. Innodb SHOW STATUS部分
12.1. Mysql5.0有一些性能計數信息經過show status可以顯示出來。
12.1.1. 它們都是全局的,雖然大部分其它技術信息都是針對每一個線程的。
12.1.2. 它們大部分都是從show innodb status中獲取的。
12.2. 下面將顯示其中的一些指標。
12.3. Innodb_buffer_pool_pages_misc–其餘緩存頁須要的在innodb buffer中所使用到的頁。
12.4. Innodb_buffer_pool_read_ahead_rnd–innodb處理的隨機預讀的數量。
12.5. Innodb_buffer_pool_read_request, innodb_buffer_pool_reads 這2個值是用來計算緩存讀的命中率的。
13. Show innodb status
13.1. 這個是innodb故障處理的工具。當發生問題時就輸入「show innodb status」
13.2. 這時候就會顯示一些比show status更詳細的信息。
13.3. 一些關於如今正在運行中的事務的信息(列入它們的鎖等等)
13.4. 最新的一個死鎖和外鍵的信息等等
13.5. 一些關於latches,spinlocks(自旋鎖),操做系統等待信息
13.6. 更詳細的參考http://www.mysqlperformanceblog.com/2006/07/17/show-innodb-status-walk-through/
14. Show mutex(互斥量) status
14.1. 一個用來顯示在你的工做負載下哪些熱門的互斥量的工具
14.2. 顯示了哪些是真正發生的互斥量,自旋鎖的細節,以及操做系統等待。
14.3. Timed_mutexes – 跟蹤操做系統等待了多久
15. 硬件和操做系統選擇的檢查列表
15.1. 使用什麼CPU,以及多少個?
15.2. 使用多大的內存?
15.3. 如何創建IO子系統(如RAID)?
15.4. 使用哪一個文件系統是最好的選擇?
16. 選擇CPU
16.1. 不一樣的CPU/架構對於innodb的擴展性能是不一樣的。
16.2. 老的「netburst」基於intel的xeon的擴展能力是比較弱的。
16.3. 新的酷睿基於xeon和 AMD的opterons具備更好的可擴張性
16.4. X86_64是很是必須的。
16.5. 使用多核處理器會讓Innodb工做的更好
16.6. 每一個系統擁有8核是一個比較合理的限制。
16.6.1. 必須根據實際的工做負載來進行調配
16.6.2. Innodb必需要根據將來的預期負載進行
16.7. 外部擴展,使用多臺性能 較低的終端服務器。
16.8. 32位的CPU立刻就要被淘汰了,因此請不要再使用32位的操做系統。
17. 使用多大的內存
17.1. 內存常常是對於很好的應用程序調優的性能瓶頸。
17.2. Innodb能夠頗有效的使用大量的內存。
17.3. 工做設定必須合理設置內存
17.3.1. 由於數據頁是最常被訪問
17.3.2. 不要經過行進行計數:100byte的行大概是1億行,隨機100萬行的工做設定可以產生大部分的數據頁。
17.4. 是總數據庫大小的5%可以致使50%空間佔用。
17.5. 肯定使用64位的平臺,操做系統和mysql版本。
18. 如何創建IO子系統
18.1. Innodb能夠很好的加載大部分的磁盤驅動。每一個節點有6-8個是一個看上去最優的配置。
18.2. 直接可以訪問到的存儲一般工做的最好
18.3. SAN–會增長恢復時間,並且價格昂貴
18.4. NAS–能夠避免不少數據錯誤的風險
18.5. ISCSI–在大部分業務中都是很是適合的,也會增長恢復時間
18.6. RAID–電池備份cache是很是重要的。必定要確認啓動了在寫入cache的時候有電池備份。
18.7. 硬盤自身的緩存通常都是須要關閉。或者確認使用fsync()寫入數據到磁盤或者當操做系統崩潰的時候可以產生數據腐壞。
19. 本地存儲的配置
19.1. 日誌最好放到單獨的raid1中。這個是很是有幫助的,在不少狀況比放在跟數據一塊兒更好。
19.2. 二進制日誌最好放到單獨的卷中–可以很好的幫助備份和恢復。
19.3. RAID10對於表空間很是好。比預期降低的性能更多。
19.4. RAID5對於特定的工做負載時好的。僅僅須要確認是否須要下降性能。
19.5. 大的RAID條帶大小(128K+)在理論是最好的,可是不少RAID控制器不能很是好的去控制。
19.6. 軟RAID也是不錯的,特別是RAID1。
20. 操做的選擇也有會有問題?
20.1. 須要考慮性能,工具的有效性,社區等等。
20.2. Windows–試用於開發環境,很低的擴展性的WEB/企業項目上。
20.3. Solaris–提供了一些很是好的工具,也能對Mysql提供很好的支持,可是缺少社區支援。
20.4. FreeBSD–歷史上Mysql有不少問題在這個平臺上,如今是好多了,可是隻有不多的工具可用,不多在生產環境中使用。
20.5. Linux–在生產環境中和開發環境中最常使用的平臺。有一些像LVM,JFS這樣的工具可使用。
21. 文件系統的選擇
21.1. 主要是linux環境中有不少文件系統能夠選擇
21.2. EXT3–不少Linux發行版的默認文件系統,工做的很是好對於終端安裝。
21.3. ReiserFS–不少Linux支持這個遷移。一般沒有打的問題在標準的Mysql工做負載下。
21.4. XFS–被用在有RAID驅動的狀況下,可以提供不錯的性能提高。
21.5. JFS–不多被使用
21.6. Raw分區(原始分區)針對innodb表空間—不多使用
21.7. 一般很是高的性能提高預期都是經過更改文件文件系統來得到。
22. InnoDB可伸縮性的補丁
22.1. 減小了buffer pool也中競爭。在5.0中直接可用,在4.1中須要本身移植。
22.2. 在MySQL5.1提高了sync_array的實現。
22.3. 基於工做負載,硬件環境,併發上的性能提高跟原來有所不一樣。
22.4. 從不多的百分比到不少次的進行排序。
22.5. 性能仍是會在很大數量的併發線程的狀況下有所降低。
22.6. 將來可擴展實現補丁的原型都是來源於社區的。
23. 其它改進
23.1. 在Mysql5.1中行級別複製減輕了間隙鎖的問題。
23.2. 在沒有auto_increment」talbe locks」可以繼續工做。
23.3. 數據庫頁中支持ZIP壓縮
23.4. 更快的索引創建
23.4.1. 再也不須要全表重建
23.4.2. 能夠根據物理分片的索引進行排序。