數據庫性能優化(MySQL)

序:

    即使有較長的緩存有效期和較理想的緩存命中率,但是緩存的創建和緩存過期後的重建都是需要訪問數據庫的。對數據庫寫操作不是很容易引入緩存策略。

11.1 查看數據庫狀態

    可以通過show status、show innodb status 來查看MySQL數據庫的狀態,使用mysqlreport這個第三方工具可使數據庫狀態報告更好看(mysqlreport本質是通過MySQL內部命令和工具來統計狀態的)。

11.2 正確使用索引

    在影響數據庫查詢性能的衆多因素中,索引絕對是一個重量級的因素,如果索引使用不當,則數據庫的其它優化可能無濟於事。

    索引是用於快速定位到表記錄所在地址的一種數據結構(BTree、Hash、RTree等)。通過索引去查找記錄即爲索引掃描。

    索引掃描不一定比全表掃描性能更好,要看情況。查詢優化器會爲一次查詢是否使用索引以及決定使用哪個索引,當然,有時查詢優化器也會犯錯誤。

    數據庫的索引需要定位到每行記錄,所有索引項的數量也會非常多,通過索引列表查找某索引項也會存在一定的小開銷。

    除了普通索引外還有唯一索引、主鍵索引、非空索引、全文索引等,不同的索引只是約束和用途不一樣。像唯一索引在插入數據時就會增加一定的開銷,因爲它每插入一次都要判斷是否重複。

    一般如果一個字段出現在查詢語句基於行的選擇、分組和排序,那麼爲該字段建立索引可能是有價值的。

    explain只可分析查詢語句,不能用於分析更新操作的語句。

    在explain中,若type爲const,說明查詢可以通過索引直接找到匹配行,key爲PRIMARY說明使用了主鍵索引。若type爲all,說明使用了全表掃描,索引未使用上,此時的key 爲空。若type爲ref,說明查詢的結果可能有多個匹配行。若type爲index,說明查詢只需要在索引中掃描即可。

    一次查詢對一個數據表只能使用一個索引,不能進行索引效應疊加。

    最左前綴是使用組合索引的最基本原則。

    非順序的索引類型如hash對order by是無效的。

    對於包含group by的查詢,數據庫一般是先將記錄分組後放到臨時表中,然後對其進行函數運算。這時若有恰當索引時,可使用索引來代替臨時表的使用。

    可以使用慢查詢配置來記錄查詢慢的語句,也可以記錄未使用索引的查詢語句。

    爲了節省查找索引的時間,可以將索引緩存起來放到內存中,這樣最理想的情況,索引可以直接在內存中查找而不需要訪問磁盤。MyISAM表包括3個文件,分別是.frm、.MYI、.MYD。也即MyISAM表類型只緩存索引不緩存數據文件。由於存在索引寫緩存機制,MyISAM表類型對於索引的寫操作存在延遲。

    在使用索引時也要考慮到其代價,索引會佔據更多的磁盤空間,有時甚至比數據文件還要大。當在建立了索引的字段上進行更新時,其索引也需要更新,這個開銷可不小。索引也需要花時間來維護。

11.3 鎖定與等待

    鎖機制是影響查詢性能的另一個因素,當多個併發用戶同時訪問同一資源時,數據庫爲保證併發訪問的一致性,使用數據庫鎖來協調訪問。

    查詢時間的開銷包括查詢本身的計算時間和查詢前的等待時間,索引影響的是前者,鎖機制影響的是後者。

    MySQL爲MyISAM表類型提供的是表鎖。表鎖允許多個線程同時讀取數據(select),但對於更新操作會排斥所有其它的查詢包括select,而且更新操作具有默認的高優先級。

    如果大部分爲查詢操作,只有少許更新操作,則不會存在太多的鎖等待。

    MySQL爲InnoDB表類型提供的是行鎖。行鎖可以帶來update和select不同線程對不同的行記錄可以併發地進行。

    行鎖並不一定比表鎖快,開銷不一定比表鎖小,尤其是涉及全表掃描時行鎖的開銷更大。

11.4 事務性表的性能

    InnoDB除了支持行鎖外,它還支持事務,InnoDB實現事務的方法是通過預寫日誌的方式。當有事務提交時,InnoDB將它寫入到內存的事務日誌緩衝區中,隨後將事務日誌寫入磁盤,從而更新實際的數據和索引。

    事務日誌寫入磁盤的時機:

    innodb_flush_log_at_trx_commit=1時,代表事務提交時事務日誌立即寫入磁盤,同時更新數據和索引。

    innodb_flush_log_at_trx_commit=0時,代表事務提交時事務日誌不立即寫入磁盤,而是每隔1秒寫入磁盤文件一次,並刷新到磁盤同時更新數據和索引。

    innodb_flush_log_at_trx_commit=2時,代表事務提交時事務日誌立即寫入磁盤文件,每隔1秒刷新到磁盤同時更新數據和索引。

    通過以上3種時機可以對比出它們的可靠性和性能。

11.5 使用查詢緩存

    查詢緩存就是將select查詢結果放在內存中,key是select語句,value是該查詢語句的結果。不論是MyISAM還是InnoDB引擎,查詢緩存都可以很好地工作,起到提升性能的作用。查詢緩存要注意緩存過期策略,在MySQL中,若一個表中有更新操作,則該表的所有查詢緩存將失效。因此,對於select密集型更新很少的應用很適合使用查詢緩存。

11.6 臨時表

    在explain查詢語句時,有時可以看到Using temporary狀態,這說明查詢過程使用了臨時表來存儲中間數據,可以通過合理使用索引來避免創建臨時表情況。若臨時表的使用不可避免,那麼也應該儘量減少臨時表本身的開銷。

    MySQL的臨時表可以創建在磁盤、內存和臨時文件中。當然,創建在磁盤上的開銷最大。有時在使用show processlist可以看到查詢狀態中有Coping to tmp table on disk,這說明MySQL在將臨時表從內存中複製到磁盤上以節省內存空間。

    可以通過tmp_table_size選項來設置用於存儲臨時表的內存空間大小。一旦空間不夠用纔會使用磁盤來存儲。

11.7 線程池

    MySQL使用多線程來處理併發連接。爲減少重複線程的創建可以儘量使用持久連接或將連接緩存起來(通過在my.cnf中配置thread_table_size=個數來設置)。

11.8 反範式設計

    所謂範式就是對關係數據庫中的關係的要求或約束,有不同程序的要求就有不同的範式。通常遵循到3NF即可,3NF就是非主鍵字段之間不能存在依賴關係,這樣可以避免刪除、更新、插入異常,保持關係的一致性,減少數據冗餘。

    反範式化就是違背關係設計的要求或約束,用於減少讀取數據的開銷,增加一定的數據冗餘,但這樣同時也增加了寫數據的開銷,因爲要保持冗餘數據的一致性。當然,爲了保證數據庫寫性能可以異步寫數據。若不想反範式則可以使用非關係型數據庫。

11.9 使用非關係數據庫

    key-value數據庫使用半結構化存儲數據,所有數據只有一個索引即key,可以將反範式化引發的數據副本保存到key-value數據庫中,這樣比關係數據庫具有更出色的併發性能。

    MemcacheDB在性能方面比較出色,是一個分佈式的key-value數據庫,使用Memcache協議,這意味着使用了Memcache的web應用可以不進行任何的修改而遷移到MemcacheDB上。

    不是所有的應用都適合用key-value數據庫,該用關係查詢的時候還是得用關係數據庫,key-value數據庫只是爲避免反範式化引發的寫數據開銷方案之一。當然,MemcacheDB封裝了Berkeley DB的複製功能,可以通過主從複製來擴展MemcacheDB的規模,提升可用性。

發佈了29 篇原創文章 · 獲贊 3 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章