MySql InnoDB 存儲引擎表優化

一、InnoDB 表存儲優化

1、OPTIMIZE TABLE

適時的使用 OPTIMIZE TABLE 語句來重組表,壓縮浪費的表空間。這是在其它優化技術不可用的情況下最直接的方法。OPTIMIZE TABLE 語句通過拷貝表數據並重建表索引,使得索引數據更加緊湊,減少空間碎片。語句的執行效果會因表的不同而不同。過大的表或者過大的索引及初次添加大量數據的情況下都會使得這一操作變慢。

2、自增主鍵

InnoDB表,如果主鍵過長(長數據列做主鍵,或者多個列組合做主鍵)會浪費很多空間。同時,二級索引也包含主鍵。這種情況,可以考慮創建自增列作爲主鍵,或者使用前綴索引。

3、VARCHAR

對於需要存儲長度不定或者包含很多NULL值的字符串列,使用 VARCHAR 代替 CHAR 。在小表應用上,緩存使用及磁盤 I/O 消耗會更小。

4、壓縮的行格式存儲

對於包含大量重複文本或者數字的大表,可以考慮採用壓縮的行格式存儲。這樣數據加載會減少對緩存及 I/O 的需求。在使用壓縮行格式前,需要考慮壓縮行格式 COMPRESSED 和的不同性能影響。

二、InnoDB 事務管理優化

優化 InnoDB 事務處理,主要需要找到事務特性和服務器負載間的某個平衡點。例如,一秒需要提交幾千事務的,或者每隔2-3個小時提交一次事務的不同應用表現。

1、AUTOCOMMIT 設置

MySQL 的默認設置 AUTOCOMMIT=1 會限制繁忙數據庫的性能。如果可以的話,可以在應用中使用 SET AUTOCOMMIT=0 或者 START TRANSACTION ,然後將多個相關的數據變更操作添加到同一事務中,然後執行 COMMIT 語句來提交事務,提交數據變更。

InnoDB 對於引發數據庫變更的操作,必須將其進行日誌刷盤。

2、只讀事務

對於只包含 SELECT 語句的事務,啓用 AUTOCOMMIT ,使得 InnoDB 能夠識別只讀事務,然後進行相應的優化。

3、回滾操作

避免對大數據量操作插入,更新和刪除之後的回滾操作。如果一個大的事務拖慢了服務器,那麼回滾將是服務器性能變得更糟。可以分批處理大數據量操作。通過殺進程方式終止的回滾操作會在服務器啓動時重新啓動。
可以通過如下策略減少此類問題發生:

  • 增大緩存,避免頻繁磁盤I/O。

  • 設置 innodb_change_buffering=all,這樣 update 和 delete 操作也會和 insert 一樣進行緩存,回滾也更快。

  • 手動commit,分割大數據操作。

爲了避免時空的回滾。增大緩存,使得回滾進程可以應用到最大的資源以便快速執行。或者殺掉回滾進程,然後使用innodb_force_recovery=3選項重啓。

對於較多執行耗時inserts, updates, 及 deletes 操作的服務器,確保innodb_change_buffering=all開啓。

4、日誌刷盤

InnoDB 如會每秒刷盤一次日誌,如果可以承受最新事務崩潰的數據損失,可以設置innodb_flush_log_at_trx_commit = 0。雖然日誌的刷盤操作也不是保證的,同時也可以設置innodb_support_xa = 0,減少磁盤和二進制日誌的同步操作。

Note

innodb_support_xa 已被棄用,將來版本會被移除。MySQL 5.7.10版本,InnoDB XA事務的兩階段提交是默認支持的,不能設置禁用innodb_support_xa。

5、耗時事務數據

行修改或刪除後,行數據及 undo logs 在物理上並沒有立刻被變更。即使在事務立刻提交後。舊數據會保持直到之前啓動的事務或者併發執行的事務完成後。這樣,這些事務可以一直訪問到相關的舊數據。所以耗時的事務會阻止 InnoDB 清除其它相關事務的數據。

6、關聯刪除

如果一個耗時的事務修改或者刪除了某些行。那麼其它使用這些數據的事務,如果事務級別設置在READ COMMITTED 或者 REPEATABLE READ 級別,則需要額外的處理來重建舊數據。

7、關聯查詢

當一個耗時的事務修改了某個表,其它使用此表的事務將不會使用覆蓋索引。如果二級索引包含比較新的PAGE_MAX_TRX_ID,或者某些記錄被標記爲已刪除,InnoDB 可能需要使用聚簇索引來查詢相應的記錄。

覆蓋索引查詢(使用二級索引即可獲得所需的數據,而不需要訪問表數據)

三、InnoDB只讀事務優化

InnoDB 可以避免給只讀事務賦 transaction ID (TRX_ID )。事務ID只對執行寫操作,或者含鎖讀操作,如 SELECT ... FOR UPDATE有用。去除不必要的事務ID,有助於減少每次讀寫操作必須訪問的內部數據結構大小。

InnoDB 在以下情景能夠識別只讀操作:

  • 事務以語句 START TRANSACTION READ ONLY 開始,這種情況下,數據變更操作會引發錯誤,事務仍會以只讀性質運行:

    ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.

    對於事務中的臨時表可以進行任何操作。

  • autocommit = on,並且事務只包含一個語句,且語句爲沒有使用FOR UPDATE 或者 LOCK IN SHARED MODE 的SELECT 語句。

  • 事務以READ ONLY 選項開始。

    這樣,對於讀繁忙的應用,如報表應用,可以將一系列的查詢語句綜合到一個只讀的事務中,或者在執行查詢前設置 autocommit = on,或者在應用中避免將變更操作和查詢操作相互影響。.

四、重做日誌(redo log)優化

可以考慮遵循以下優化指引:

1、日誌大小

確保重做日誌足夠大,即使和緩存池(buffer pool)一樣大。當 InnoDB 寫滿 redo log 時,服務器會基於一個檢查點(checkpoint)就會將日誌中的變更內容寫到磁盤。如果 redo log 文件過小,那麼就會引發服務器頻繁的寫盤。雖然之前,設置過大的 redo log 會引起恢復時間的過長,但是現在,恢復機制已經在速度上有很大的優化,因此不用再考慮此因素。
文件的大小和數量可以使用: innodb_log_file_size 和 innodb_log_files_in_group 進行設置。

2、日誌緩存

可以考慮增大日誌緩存(log buffer)。大的日誌緩存可以容納更大的事務執行,避免不必要的寫盤操作。設置變量:innodb_log_buffer_size 。

3、read-on-write

配置 innodb_log_write_ahead_size 變量以避免 “read-on-write”(就是當修改的字節不足一個洗系統 block時,需要將整個 block 讀進內存,修改對應的位置,然後再寫進去;如果我們以 block 爲單位來寫入的話,直接完整覆蓋寫入即可)。這個配置定義了 redo log 的 write-ahead 塊大小。

設置innodb_log_write_ahead_size 的大小以匹配操作系統或者文件系統的緩存塊大小。

Read-on-write 的產生是因爲在 write-ahead 塊大小和操作系統或者文件系統的緩存塊大小不匹配的情況下,redo log 塊無法完全的寫入到操作系統,或者文件系統引起的。

innodb_log_write_ahead_size 的值可以設置爲 InnoDB 日誌文件塊大小的倍數(2n)。最小的值爲(512)。設置爲最小值時 Write-ahead 不會發生。最大值爲 innodb_page_size 。如果設置的值大於innodb_page_size,那麼服務器會使用innodb_page_size值。

innodb_log_write_ahead_size 值設置的太小,會導致 read-on-write;設置過大,則會影響 fsync 性能,因爲一次需要些多個數據塊。

五、InnoDB表的大數據載入

快速插入通用指引:

1、AUTOCOMMIT

導入數據時,關閉 autocommit 模式,避免每次行插入導致的日誌刷盤。在執行開始及結束使用 SET AUTOCOMMIT 及 COMMIT 語句:

SET autocommit=0;
...SQLimport statements ...
COMMIT;

mysqldump 選項 --opt (默認啓用)會創建 dump 轉儲 文件,以執行快速數據導入,避免將所有的數據載入內存引發問題。即使不使用SET autocommit 和 COMMIT。

2、二級索引鍵 UNIQUE 限制

如果在二級索引鍵上有 UNIQUE 限制,可以在載入時暫時關閉此檢查:

SET unique_checks=0;
...SQLimport statements ...
SET unique_checks=1;

對於較大的表,此操作可以節省大量的磁盤 I/O,因爲 InnoDB 可以使用它的 change buffer(change buffer 的主要目的是將對二級索引的數據操作緩存下來,以此減少二級索引的隨機IO,並達到操作合併的效果)來批量寫二級索引記錄。確保數據不包含重複鍵。

3、FOREIGN KEY

如果表鍵包含 FOREIGN KEY 限制。可以再導入期間關閉此限制。

4、批量多行插入

使用批量多行插入,以減少不必要客戶端服務器間通信:

SET foreign_key_checks=0;
...SQLimport statements ...
SET foreign_key_checks=1;

INSERT INTO yourtable VALUES (1,2), (5,5), ...;

適用於任何類型表。

5、自增列批量插入

當批量插入涉及自增列時,設置 innodb_autoinc_lock_mode = 2 (默認1,0:traditional;1:consecutive;2:interleaved)。

6、主鍵順序插入

以主鍵的順序進行批量插入會更快。InnoDB 表主鍵索引爲聚簇索引(clustered index, 以主鍵的順序訪問會很快)。特別是對於無法完全載入緩存的大表。

7、全文索引

全文索引導入:

  • 表創建時定義新列FTS_DOC_ID,類型 BIGINT UNSIGNED NOT NULL,,列上定義索引FTS_DOC_ID_INDEX,如下:

    CREATE TABLE t1 (

    FTS_DOC_ID BIGINT unsigned NOT NULL AUTO_INCREMENT,

    title varchar(255) NOT NULL DEFAULT '',

    text mediumtext NOT NULL,

    PRIMARY KEY ('FTS_DOC_ID')

    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;CREATE UNIQUE INDEX FTS_DOC_ID_INDEX on t1(FTS_DOC_ID);

  • 載入數據。

  • 數據載入後,在相應的列上創建全文索引。

    Note

    在 innodb 存儲引擎中,爲了支持全文檢索,必須有一個列與 word 進行映射,在 innodb 中這個列被命名爲FTS_DOC_ID,其類型必須爲 BIGINT UNSIGNED NOT NULL,並且 innodb 存儲引擎會在該列上加上一個名爲FTS_DOC_ID_INDEX 的唯一索引。上述操作由 innodb 存儲引擎自己完成,用戶也可以在創建表時手動添加,主要對應的約束條件。

常規的索引是文檔到關鍵詞的映射:文檔——>關鍵詞

倒排索引是關鍵詞到文檔的映射:關鍵詞——>文檔

全文索引通過關鍵字找到關鍵字所在文檔,可以提高查詢效率

六、InnoDB 查詢優化

創建適當的索引以優化查詢,通用指引如下:

  • 將關鍵查詢最常用的的列包含進表主鍵中。

  • 主鍵列不要使用過多的列或者過長的列。因爲二級索引包含主鍵,過大的主鍵會造成磁盤I/O及內存的浪費。

  • 不要在每個列上創建二級索引,一個查詢只能使用一個索引。對於極少使用的列及列選擇性不大的列創建索引對於查詢優化不會有太大幫助。如果針對一個表的查詢非常多,則需要找到能夠有助於最多查詢的多列主鍵。如果索引列能夠覆蓋所需要查詢的數據列,那麼就可以只使用索引進行數據查詢,而不需要從表中獲取數據。

  • 如果某一列的數據不能爲NULL,那麼在創建表的時候將其生命爲 NOT NULL 。優化器以此可以更高的決定最優使用索引。

  • 可以針對但查詢事務進行相應的優化。

七、InnoDB DDL 操作優化

  • 許多DDL操作,如表和索引的(CREATE, ALTER, 及DROP 語句) 可以在線執行。

  • 使用 TRUNCATE TABLE 代替 DELETE FROM tbl_name 來清空表,外鍵限制可以使得 TRUNCATE 語句如普通的 DELETE 語句般操作。這種情景下,一系列如 DROP TABLE 及 CREATE TABLE 語句會執行的很快。

  • 因爲主鍵InnoDB表的存儲結構是高度整合的,主鍵的變更會引起整張表的重構。最好將主鍵定義包含在表創建語句中,避免不必要的後期更改。

八、InnoDB 磁盤 I/O 優化

如果數據庫的設計及 sql 操作優化都遵循了最佳實踐,數據庫依然因爲 I/O 負載而反應非常慢,那麼就需要針對 I/O 進行專門的優化。可以通過 Unix 的 top 工具,或者 Windows 的任務管理器來查看工作負載,如果低 於70%,那麼負載則主要在磁盤。

1、增大緩存:

InnoDB 緩存中的數據訪問不需要磁盤I/O,使用innodb_buffer_pool_size 設置。建議設置爲系統內存的 50 ~ 75%。

2、調整刷盤策略:

某些版本 GNU/Linux 系統,使用fsync() 或者相關方法進行刷盤時,速度會非常慢。這時,如果影響到數據庫性能,那麼可以通過設置innodb_flush_method = O_DSYNC 來變更刷盤策略。

3、調整 Linux 系統 AIO 磁盤調度策略爲 noop(單隊列) 或者deadline(讀、寫隊列)

InnoDB 在 Linux 系統上使用異步 I/O 子系統(本地AIO)通過預讀和寫請求來執行數據文件讀寫。配置變量innodb_use_native_aio 默認啓用。磁盤調度策略對本地 AIO 影響比較大。通常建議設置爲 noop 或者 deadline。

4、Solaris 10 x86_64架構建議使用direct I/O策略

5、RAID配置

6、non-rotational 存儲

Non-rotational 存儲適用於隨機讀寫;rotational 存儲相反適用於順序讀寫。不同的存儲設備對數據及日誌的操作類型不同。

數據庫隨機讀寫類文件包括:file-per-table 和 general tablespace 數據文件, undo tablespace文件和temporary tablespace 文件。順序讀寫類文件包括:InnoDB system tablespace 文件(基於 doublewrite buffering and change buffering) 及日誌文件( binary log 文件和redo log 文件等)。

使用 non-rotational 存儲時,需要對以下配置進行優化:

  • innodb_checksum_algorithm:crc32 算法使用了一種更快的一致性檢查算法,對於高速存儲設備,推薦使用。

  • innodb_flush_neighbors:針對rotational存儲設備優化。對於non-rotational設備或者混用情景,則需禁用。

  • innodb_io_capacity:默認的200設定對於低端non-rotational存儲設備已經足夠。其它,酌情設置。

  • innodb_io_capacity_max:默認2000 針對non-rotational 存儲。

  • innodb_log_compressed_pages:如果redo logs存儲在non-rotational設備,可以開率禁用詞選項來減少日誌。

  • innodb_log_file_size:如果redo logs 存儲在non-rotational 存儲設備,設置此選項最大讀寫緩存。

  • innodb_page_size:設置此值以匹配磁盤internal sector size。早期的SSD設備爲4KB,一些新版本的SSD能夠支持到16KB。默認的額InnoDB 也大小爲16KB。儘量使得數據庫頁大小和存儲設備的塊大小接近,減少無法一次寫入磁盤的數據大小。

  • binlog_row_image:binary logs 存儲在non-rotational 設備情況下,如果所有的表都有主鍵,那麼可以將此變量設置爲最小來減少日誌。

7、增大 I/O 容量以減少 backlogs 負載

如果吞吐量會因爲檢測點操作而不間斷的降低,那麼可以開率增加 innodb_io_capacity 的值。值越大,數據庫刷盤頻率會增大,從而避免了因爲 backlog 的操作帶來的吞吐量的影響。

8、調整數據庫I/O容量

如果系統能夠滿足 InnoDB 刷盤操作。可以考慮減小innodb_io_capacity 配置。通常需要將此變量儘量設置低一些。(SHOW ENGINE INNODB STATUS)

9、將系統表空間文件存儲在 Fusion-io設備

如果使用支持原子寫的 Fusion-io 設備存儲系統表空間文件(“ibdata files”) ,那麼可以對 doublewrite buffer-related I/O進行相應的優化。這種情況下,會自動使用 Fusion-io 設備的原子寫替代 doublewrite buffering (innodb_doublewrite)進行數據的讀寫。這種特性只支持 Fusion-io 硬件設備及 Fusion-io NVMFS Linux 應用。可以通過變量 innodb_flush_method = O_DIRECT 進行配置。

Note

設置是全局性的,影響所有設備上的數據讀寫。

10、禁用壓縮數據頁日誌

使用 InnoDB 表壓縮特性時,重新壓縮的圖片數據頁,如果數據有變化,則會寫入 redo log。配置變量innodb_log_compressed_pages 默認啓用,防止數據庫恢復期間,因爲 zlib 算法的變化引發數據庫崩潰。如果可以確認 zlib 版本不會發生變化,那麼可以關閉 innodb_log_compressed_pages 變量來減少重壓縮產生的 redo log 負載。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章