淺談MySQL優化與學習

原文出自:57CTO技術論壇


一、我們可以且應該優化什麼?

硬件  
操作系統/軟件庫  
SQL服務器(設置和查詢)  
應用編程接口(API)  
應用程序  
--------------------------------------------------------------------------------
二、優化硬件
如果你需要龐大的數據庫表(>2G),你應該考慮使用64位的硬件結構,像Alpha、Sparc或即將推出的IA64。因爲MySQL內部使用大量64位的整數,64位的CPU將提供更好的性能。  
對大數據庫,優化的次序一般是RAM、快速硬盤、CPU能力。  
更多的內存通過將最常用的鍵碼頁面存放在內存中可以加速鍵碼的更新。  
如果不使用事務安全(transaction-safe)的表或有大表並且想避免長文件檢查,一臺UPS就能夠在電源故障時讓系統安全關閉。  
對於數據庫存放在一個專用服務器的系統,應該考慮1G的以太網。延遲與吞吐量同樣重要。  
--------------------------------------------------------------------------------
三、優化磁盤
爲系統、程序和臨時文件配備一個專用磁盤,如果確是進行很多修改工作,將更新日誌和事務日誌放在專用磁盤上。
低尋道時間對數據庫磁盤非常重要。對與大表,你可以估計你將需要log(行數)/log(索引塊長度/3*2/(鍵碼長度 + 數據指針長度))+1次尋到才能找到一行。對於有500000行的表,索引Mediun int類型的列,需要log(500000) / log(1024/3*2/(3 + 2))+1=4次尋道。上述索引需要500000*7*3/2=5.2M的空間。實際上,大多數塊將被緩存,所以大概只需要1-2次尋道。
然而對於寫入(如上),你將需要4次尋道請求來找到在哪裏存放新鍵碼,而且一般要2次尋道來更新索引並寫入一行。
對於非常大的數據庫,你的應用將受到磁盤尋道速度的限制,隨着數據量的增加呈N log N數據級遞增。
將數據庫和表分在不同的磁盤上。在MySQL中,你可以爲此而使用符號鏈接。
條列磁盤(RAID 0)將提高讀和寫的吞吐量。
帶鏡像的條列(RAID 0+1)將更安全並提高讀取的吞吐量。寫入的吞吐量將有所降低。
不要對臨時文件或可以很容易地重建的數據所在的磁盤使用鏡像或RAID(除了RAID 0)。
在Linux上,在引導時對磁盤使用命令hdparm -m16 -d1以啓用同時讀寫多個扇區和DMA功能。這可以將響應時間提高5~50%。
在Linux上,用async (默認)和noatime掛載磁盤(mount)。
對於某些特定應用,可以對某些特定表使用內存磁盤,但通常不需要。  
--------------------------------------------------------------------------------
四、優化操作系統
不要交換區。如果內存不足,增加更多的內存或配置你的系統使用較少內存。
不要使用NFS磁盤(會有NFS鎖定的問題)。
增加系統和MySQL服務器的打開文件數量。(在safe_mysqld腳本中加入ulimit -n #)。
增加系統的進程和線程數量。
如果你有相對較少的大表,告訴文件系統不要將文件打碎在不同的磁道上(Solaris)。
使用支持大文件的文件系統(Solaris)。
選擇使用哪種文件系統。在Linux上的Reiserfs對於打開、讀寫都非常快。文件檢查只需幾秒種。  
--------------------------------------------------------------------------------
五、選擇應用編程接口
PERL
可在不同的操作系統和數據庫之間移植。
適宜快速原型。
應該使用DBI/DBD接口。
PHP
比PERL易學。
使用比PERL少的資源。
通過升級到PHP4可以獲得更快的速度。
C
MySQL的原生接口。
較快並賦予更多的控制。
低層,所以必須付出更多。
C++
較高層次,給你更多的時間來編寫應用。
仍在開發中
ODBC
運行在Windows和Unix上。
幾乎可在不同的SQL服務器間移植。
較慢。MyODBC只是簡單的直通驅動程序,比用原生接口慢19%。
有很多方法做同樣的事。很難像很多ODBC驅動程序那樣運行,在不同的領域還有不同的錯誤。
問題成堆。Microsoft偶爾還會改變接口。
不明朗的未來。(Microsoft更推崇OLE而非ODBC)
ODBC
運行在Windows和Unix上。
幾乎可在不同的SQL服務器間移植。
較慢。MyODBC只是簡單的直通驅動程序,比用原生接口慢19%。
有很多方法做同樣的事。很難像很多ODBC驅動程序那樣運行,在不同的領域還有不同的錯誤。
問題成堆。Microsoft偶爾還會改變接口。
不明朗的未來。(Microsoft更推崇OLE而非ODBC)
JDBC
理論上可在不同的操作系統何時據庫間移植。
可以運行在web客戶端。
Python和其他
可能不錯,可我們不用它們。  
--------------------------------------------------------------------------------
六、優化應用
應該集中精力解決問題。
在編寫應用時,應該決定什麼是最重要的:
速度
操作系統間的可移植性
SQL服務器間的可移植性
使用持續的連接。.
緩存應用中的數據以減少SQL服務器的負載。
不要查詢應用中不需要的列。
不要使用SELECT * FROM table_name...
測試應用的所有部分,但將大部分精力放在在可能最壞的合理的負載下的測試整體應用。通過以一種模塊化的方式進行,你應該能用一個快速“啞模塊”替代找到的瓶頸,然後很容易地標出下一個瓶頸。
如果在一個批處理中進行大量修改,使用LOCK TABLES。例如將多個UPDATES或DELETES集中在一起。  
--------------------------------------------------------------------------------
七、應該使用可移植的應用
Perl DBI/DBD
ODBC
JDBC
Python(或其他有普遍SQL接口的語言)
你應該只使用存在於所有目的SQL服務器中或可以很容易地用其他構造模擬的SQL構造。www.mysql.com上的Crash-me頁可以幫助你。
爲操作系統/SQL服務器編寫包裝程序來提供缺少的功能。  
--------------------------------------------------------------------------------
八、如果你需要更快的速度,你應該:
找出瓶頸(CPU、磁盤、內存、SQL服務器、操作系統、API或應用)並集中全力解決。
使用給予你更快速度/靈活性的擴展。
逐漸瞭解SQL服務器以便能爲你的問題使用可能最快的SQL構造並避免瓶頸。
優化表佈局和查詢。
使用複製以獲得更快的選擇(select)速度。
如果你有一個慢速的網絡連接數據庫,使用壓縮客戶/服務器協議。
不要害怕時應用的第一個版本不能完美地移植,在你解決問題時,你總是可以在以後優化它。  
--------------------------------------------------------------------------------
九、優化MySQL
挑選編譯器和編譯選項。
位你的系統尋找最好的啓動選項。
通讀MySQL參考手冊並閱讀Paul DuBios的《MySQL》一書。(已有中文版-譯註)
多用EXPLAIN SELECT、SHOW VARIABLES、SHOW STATUS和SHOW PROCESSLIST。
瞭解查詢優化器的工作原理。
優化表的格式。
維護你的表(myisamchk、CHECK TABLE、 OPTIMIZE TABLE)
使用MySQL的擴展功能以讓一切快速完成。
如果你注意到了你將在很多場合需要某些函數,編寫MySQL UDF函數。
不要使用表級或列級的GRANT,除非你確實需要。
購買MySQL技術支持以幫助你解決問題
--------------------------------------------------------------------------------
十、編譯和安裝MySQL
通過位你的系統挑選可能最好的編譯器,你通常可以獲得10-30%的性能提高。
在Linux/Intel平臺上,用pgcc(gcc的奔騰芯片優化版)編譯MySQL。然而,二進制代碼將只能運行在Intel奔騰CPU上。
對於一種特定的平臺,使用MySQL參考手冊上推薦的優化選項。
一般地,對特定CPU的原生編譯器(如Sparc的Sun Workshop)應該比gcc提供更好的性能,但不總是這樣。
用你將使用的字符集編譯MySQL。
靜態編譯生成mysqld的執行文件(用--with-mysqld-ldflags=all-static)並用strip sql/mysqld整理最終的執行文件。
注意,既然MySQL不使用C++擴展,不帶擴展支持編譯MySQL將贏得巨大的性能提高。
如果操作系統支持原生線程,使用原生線程(而不用mit-pthreads)。
用MySQL基準測試來測試最終的二進制代碼。  
--------------------------------------------------------------------------------
十一、維護
如果可能,偶爾運行一下OPTIMIZE table,這對大量更新的變長行非常重要。
偶爾用myisamchk -a更新一下表中的鍵碼分佈統計。記住在做之前關掉MySQL。
如果有碎片文件,可能值得將所有文件複製到另一個磁盤上,清除原來的磁盤並拷迴文件。
如果遇到問題,用myisamchk或CHECK table檢查表。
用mysqladmin -i10 precesslist extended-status監控MySQL的狀態。
用MySQL GUI客戶程序,你可以在不同的窗口內監控進程列表和狀態。
使用mysqladmin debug獲得有關鎖定和性能的信息。  
--------------------------------------------------------------------------------
十二、優化SQL
揚SQL之長,其它事情交由應用去做。使用SQL服務器來做:
找出基於WHERE子句的行。
JOIN表
GROUP BY
ORDER BY
DISTINCT
不要使用SQL來做:
檢驗數據(如日期)
成爲一隻計算器
技巧:
明智地使用鍵碼。
鍵碼適合搜索,但不適合索引列的插入/更新。
保持數據爲數據庫第三範式,但不要擔心冗餘信息或這如果你需要更快的速度,創建總結表。
在大表上不做GROUP BY,相反創建大表的總結表並查詢它。
UPDATE table set count=count+1 where key_column=constant非常快。
對於大表,或許最好偶爾生成總結表而不是一直保持總結表。
充分利用INSERT的默認值。  
--------------------------------------------------------------------------------
十三、不同SQL服務器的速度差別(以秒計)

通過鍵碼讀取2000000行: NT Linux
mysql 367 249
mysql_odbc 464  
db2_odbc 1206  
informix_odbc 121126  
ms-sql_odbc 1634  
oracle_odbc 20800  
solid_odbc 877  
sybase_odbc 17614  

插入350768行: NT Linux
mysql 381 206
mysql_odbc 619  
db2_odbc 3460  
informix_odbc 2692  
ms-sql_odbc 4012  
oracle_odbc 11291  
solid_odbc 1801  
sybase_odbc 4802    
在上述測試中,MySQL配置8M高速緩存運行,其他數據庫以默認安裝運行。  
--------------------------------------------------------------------------------
十四、重要的MySQL啓動選項
back_log 如果需要大量新連接,修改它。
thread_cache_size 如果需要大量新連接,修改它。
key_buffer_size 索引頁池,可以設成很大。
bdb_cache_size BDB表使用的記錄和鍵嗎高速緩存。
table_cache 如果有很多的表和併發連接,修改它。
delay_key_write 如果需要緩存所有鍵碼寫入,設置它。
log_slow_queries 找出需花大量時間的查詢。
max_heap_table_size 用於GROUP BY
sort_buffer 用於ORDER BY和GROUP BY
myisam_sort_buffer_size 用於REPAIR TABLE
join_buffer_size 在進行無鍵嗎的聯結時使用。  
--------------------------------------------------------------------------------
十五、優化表
MySQL擁有一套豐富的類型。你應該對每一列嘗試使用最有效的類型。
ANALYSE過程可以幫助你找到表的最優類型:SELECT * FROM table_name PROCEDURE ANALYSE()。
對於不保存NULL值的列使用NOT NULL,這對你想索引的列尤其重要。
將ISAM類型的表改爲MyISAM。
如果可能,用固定的表格式創建表。
不要索引你不想用的東西。
利用MySQL能按一個索引的前綴進行查詢的事實。如果你有索引INDEX(a,b),你不需要在a上的索引。
不在長CHAR/VARCHAR列上創建索引,而只索引列的一個前綴以節省存儲空間。CREATE TABLE table_name (hostname CHAR(255) not null, index(hostname(10)))
對每個表使用最有效的表格式。
在不同表中保存相同信息的列應該有同樣的定義並具有相同的列名。  
--------------------------------------------------------------------------------
十六、MySQL如何次存儲數據
數據庫以目錄存儲。
表以文件存儲。
列以變長或定長格式存儲在文件中。對BDB表,數據以頁面形式存儲。
支持基於內存的表。
數據庫和表可在不同的磁盤上用符號連接起來。
在Windows上,MySQL支持用.sym文件內部符號連接數據庫。


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