咱們從系統級因素開始,由於必須儘早地進行部分決策以得到較大性能。在其它狀況下,快速瀏覽該節就足夠了。可是,瞭解一下更改該層次的參數可以得到多少性 能提升是頗有意義的。html
使用的操做系統很重要。爲了更好地使用多CPU機器,應使用Solaris(由於其線程工做 得很好)或Linux(由於2.4和之後的內核有很好的SMP支 持)。請注意默認狀況舊的Linux內核有一個2GB的文件大小限制。 若是有這樣的一個內核而且須要文件大於2GB,應獲得ext2文件系統的大文件支持(LFS)補 丁。其它文件系統例如ReiserFS和XFS沒有此2GB限制。node
將MySQL用於生產前,咱們建議你在想用的平臺上對它進行測試。mysql
其它技巧:c++
· 若是有足夠的RAM,能夠移除全部的交換設備。有些操做系統即便有自由內存也使用交換設 備。算法
· 使用--skip-external-locking MySQL選項以免外部鎖定。該選項默認開啓。sql
請注意只要你只運行一個服務器,--skip-external-locking選項不影響MySQL的 功能。只要記住運行myisamchk以前關閉服務器(或鎖定 並刷新相關表)。在一些系統上該選項是強制的,由於在任何狀況下外部鎖定均不工做。shell
不能使用--skip-external-locking的惟一狀況是對相同的數據運行多個MySQL服 務器(非客戶)的狀況,或者若是沒有事先告訴服務器刷新並鎖定一個表即運行myisamchk來 檢查(非修復)該表。請注意通常不建議使用多個MySQL服務器來並行 訪問相同的數據,除了使用MySQL Cluster時。緩存
即便使用--skip-external-locking,仍然可使用LOCK TABLES和UNLOCK TABLES。安全
能夠用這個命令獲得mysqld服務器 默認緩存區的大小:服務器
shell> mysqld --verbose --help
這個命令生成全部mysqld選項和可配置變量的列表。輸出包括 默認值而且看上去象這樣:
help TRUE
abort-slave-event-count 0
allow-suspicious-udfs FALSE
auto-increment-increment 1
auto-increment-offset 1
automatic-sp-privileges TRUE
basedir /home/jon/bin/mysql/
bdb FALSE
bind-address (No default value)
character-set-client-handshake TRUE
character-set-server latin1
character-sets-dir /home/jon/bin/mysql/share/mysql/charsets/
chroot (No default value)
collation-server latin1_swedish_ci
completion-type 0
concurrent-insert 1
console FALSE
datadir /home/jon/bin/mysql/var/
default-character-set latin1
default-collation latin1_swedish_ci
default-time-zone (No default value)
disconnect-slave-event-count 0
enable-locking FALSE
enable-pstack FALSE
engine-condition-pushdown FALSE
external-locking FALSE
gdb FALSE
large-pages FALSE
init-connect (No default value)
init-file (No default value)
init-slave (No default value)
innodb TRUE
innodb_checksums TRUE
innodb_data_home_dir (No default value)
innodb_doublewrite TRUE
innodb_fast_shutdown 1
innodb_file_per_table FALSE
innodb_flush_log_at_trx_commit 1
innodb_flush_method (No default value)
innodb_locks_unsafe_for_binlog FALSE
innodb_log_arch_dir (No default value)
innodb_log_group_home_dir (No default value)
innodb_max_dirty_pages_pct 90
innodb_max_purge_lag 0
innodb_status_file FALSE
innodb_table_locks TRUE
innodb_support_xa TRUE
isam FALSE
language /home/jon/bin/mysql/share/mysql/english
local-infile TRUE
log /home/jon/bin/mysql/var/master1.log
log-bin /home/jon/bin/mysql/var/master1
log-bin-index (No default value)
log-bin-trust-routine-creators FALSE
log-error /home/jon/bin/mysql/var/master1.err
log-isam myisam.log
log-queries-not-using-indexes FALSE
log-short-format FALSE
log-slave-updates FALSE
log-slow-admin-statements FALSE
log-slow-queries (No default value)
log-tc tc.log
log-tc-size 24576
log-update (No default value)
log-warnings 1
low-priority-updates FALSE
master-connect-retry 60
master-host (No default value)
master-info-file master.info
master-password (No default value)
master-port 3306
master-retry-count 86400
master-ssl FALSE
master-ssl-ca (No default value)
master-ssl-capath (No default value)
master-ssl-cert (No default value)
master-ssl-cipher (No default value)
master-ssl-key (No default value)
master-user test
max-binlog-dump-events 0
memlock FALSE
myisam-recover OFF
ndbcluster FALSE
ndb-connectstring (No default value)
ndb-mgmd-host (No default value)
ndb-nodeid 0
ndb-autoincrement-prefetch-sz 32
ndb-distibution KEYHASH
ndb-force-send TRUE
ndb_force_send TRUE
ndb-use-exact-count TRUE
ndb_use_exact_count TRUE
ndb-shm FALSE
ndb-optimized-node-selection TRUE
ndb-cache-check-time 0
ndb-index-stat-enable TRUE
ndb-index-stat-cache-entries 32
ndb-index-stat-update-freq 20
new FALSE
old-alter-table FALSE
old-passwords FALSE
old-style-user-limits FALSE
pid-file /home/jon/bin/mysql/var/hostname.pid1
port 3306
relay-log (No default value)
relay-log-index (No default value)
relay-log-info-file relay-log.info
replicate-same-server-id FALSE
report-host (No default value)
report-password (No default value)
report-port 3306
report-user (No default value)
rpl-recovery-rank 0
safe-user-create FALSE
secure-auth FALSE
server-id 1
show-slave-auth-info FALSE
skip-grant-tables FALSE
skip-slave-start FALSE
slave-load-tmpdir /tmp/
socket /tmp/mysql.sock
sporadic-binlog-dump-fail FALSE
sql-mode OFF
symbolic-links TRUE
tc-heuristic-recover (No default value)
temp-pool TRUE
timed_mutexes FALSE
tmpdir (No default value)
use-symbolic-links TRUE
verbose TRUE
warnings 1
back_log 50
binlog_cache_size 32768
bulk_insert_buffer_size 8388608
connect_timeout 5
date_format (No default value)
datetime_format (No default value)
default_week_format 0
delayed_insert_limit 100
delayed_insert_timeout 300
delayed_queue_size 1000
expire_logs_days 0
flush_time 0
ft_max_word_len 84
ft_min_word_len 4
ft_query_expansion_limit 20
ft_stopword_file (No default value)
group_concat_max_len 1024
innodb_additional_mem_pool_size 1048576
innodb_autoextend_increment 8
innodb_buffer_pool_awe_mem_mb 0
innodb_buffer_pool_size 8388608
innodb_concurrency_tickets 500
innodb_file_io_threads 4
innodb_force_recovery 0
innodb_lock_wait_timeout 50
innodb_log_buffer_size 1048576
innodb_log_file_size 5242880
innodb_log_files_in_group 2
innodb_mirrored_log_groups 1
innodb_open_files 300
innodb_sync_spin_loops 20
innodb_thread_concurrency 20
innodb_commit_concurrency 0
innodb_thread_sleep_delay 10000
interactive_timeout 28800
join_buffer_size 131072
key_buffer_size 8388600
key_cache_age_threshold 300
key_cache_block_size 1024
key_cache_division_limit 100
long_query_time 10
lower_case_table_names 0
max_allowed_packet 1048576
max_binlog_cache_size 4294967295
max_binlog_size 1073741824
max_connect_errors 10
max_connections 100
max_delayed_threads 20
max_error_count 64
max_heap_table_size 16777216
max_join_size 4294967295
max_length_for_sort_data 1024
max_relay_log_size 0
max_seeks_for_key 4294967295
max_sort_length 1024
max_tmp_tables 32
max_user_connections 0
max_write_lock_count 4294967295
multi_range_count 256
myisam_block_size 1024
myisam_data_pointer_size 6
myisam_max_extra_sort_file_size 2147483648
myisam_max_sort_file_size 2147483647
myisam_repair_threads 1
myisam_sort_buffer_size 8388608
myisam_stats_method nulls_unequal
net_buffer_length 16384
net_read_timeout 30
net_retry_count 10
net_write_timeout 60
open_files_limit 0
optimizer_prune_level 1
optimizer_search_depth 62
preload_buffer_size 32768
query_alloc_block_size 8192
query_cache_limit 1048576
query_cache_min_res_unit 4096
query_cache_size 0
query_cache_type 1
query_cache_wlock_invalidate FALSE
query_prealloc_size 8192
range_alloc_block_size 2048
read_buffer_size 131072
read_only FALSE
read_rnd_buffer_size 262144
div_precision_increment 4
record_buffer 131072
relay_log_purge TRUE
relay_log_space_limit 0
slave_compressed_protocol FALSE
slave_net_timeout 3600
slave_transaction_retries 10
slow_launch_time 2
sort_buffer_size 2097144
sync-binlog 0
sync-frm TRUE
sync-replication 0
sync-replication-slave-id 0
sync-replication-timeout 10
table_cache 64
table_lock_wait_timeout 50
thread_cache_size 0
thread_concurrency 10
thread_stack 196608
time_format (No default value)
tmp_table_size 33554432
transaction_alloc_block_size 8192
transaction_prealloc_size 4096
updatable_views_with_limit 1
wait_timeout 28800
若是有一個mysqld服務器正在運行,經過鏈接它並執行這個命令,能夠看到 實際上使用的變量的值:
mysql> SHOW VARIABLES;
還能夠經過下面的語句看到運行服務器的統計和狀態指標:
mysql>SHOW STATUS;
使用mysqladmin還能夠得到系統變量和狀態信息:
shell> mysqladmin variables
shell> mysqladmin extended-status
關於全部系統和狀態變量的徹底描述參見5.3.3節,「服務器系統變量」和5.3.4節,「服務器狀態變量」。
MySQL使用徹底能夠升級的算法,所以一般運行時能夠用不多的內存。然而,一般狀況若給MySQL更 多的內存性能會更好。
當調節MySQL服務器時,要配置的兩個最重要的變量是key_buffer_size和table_cache。 在試圖更改其它變量前你應先確信已經適當地配置了這些變量。
下面的例子顯示了部分典型的不一樣的運行時配置的變量值。
· 若是至少有256MB內存和許多表,想要在中等數量的客戶時得到最大性能,應使用:
· shell> mysqld_safe --key_buffer_size=64M --table_cache=256 \
· --sort_buffer_size=4M --read_buffer_size=1M &
· 若是隻有128MB內存和少許表,但仍然要進行大量的排序,可使用:
· shell> mysqld_safe --key_buffer_size=16M --sort_buffer_size=1M
若是有許多並行鏈接,交換問題會發生,除非mysqld已經配置成爲每一個鏈接分配很 少的內存。若是有足夠的內存用於全部鏈接,mysqld會執行得更好。
· 對於少許內存和大量鏈接,應使用:
· shell> mysqld_safe --key_buffer_size=512K --sort_buffer_size=100K \
· --read_buffer_size=100K &
或甚至爲:
shell> mysqld_safe --key_buffer_size=512K --sort_buffer_size=16K \
--table_cache=32 --read_buffer_size=8K \
--net_buffer_length=1K &
若是正對遠遠大於可用內存的表執行GROUP BY或ORDER BY操做,應增長read_rnd_buffer_size的值以加速排序操 做後面的行讀取。
若是已經安裝了MySQL,support-files目錄包含一些不一樣的my.cnf示 例文件:my-huge.cnf、my-大.cnf、my-medium.cnf和my-small.cnf。 可使用這些文件來優化系統。
請注意若是在命令行中爲mysqld或mysqld_safe指 定一個選項,它只在該次服務器調用中保持有效。要想每次服務器運行時使用該選項,將它放在選項文件中。
要想看參數更改的效果,應執行:
shell> mysqld --key_buffer_size=32M --verbose ---help
變量值列於輸出的最後。確保--verbose和---help選項在最後。不然,在命令行 中列於它們後面的選項的效果不會反映到輸出中。
關於調節InnoDB存儲引擎的信息,參見15.2.11節,「InnoDB性能調節提示」。
查詢優化器的任務是發現執行SQL查詢的最佳方案。由於「好」 方案和「壞」方案之間的性能差異會巨大(也就是說,秒相對於小時或甚 至天),大多數查詢優化器,包括MySQL的查詢優化器,總或多或少地在全部可能的查詢評估方案中 搜索最佳方案。對於聯接查詢,MySQL優化器所調查的可能的方案數隨查詢中所引用的表的數目呈指數增加。對於小數量的表(典 型小於7-10),這不是一個問題。然而,當提交的查詢更大時,查詢優化所花的時間會很容易地成爲服務器性能的主要瓶頸。
查詢優化的一個更加靈活的方法是容許用戶控制優化器詳盡地搜索最佳查詢評估方案。通常思想是優化器調查的方案越少,它編譯一個查詢所花費的時間越少。另外一 方面,由於優化器跳過了一些方案,它可能錯過一個最佳方案。
優化器關於方案數量評估的行爲能夠經過兩個系統變量來控制:
· optimizer_prune_level變量告訴優化器根據對每一個表訪問的行數的估計跳過某些方案。咱們的試驗顯示 該類「有根據的猜想」不多錯過最佳方案,而且能夠大大下降查詢編輯次數。這就是爲何默認狀況該 選項爲on(optimizer_prune_level=1)。然 而,若是你認爲優化器錯過了一個更好的查詢方案,則該選項能夠關閉(optimizer_prune_level=0), 風險是查詢編輯花費的時間更長。請注意即便使用該啓發,優化器仍然能夠探測呈指數數目的方案。
· optimizer_search_depth變量告訴優化器對於每一個未完成的「將來的」方案,應查看多深,以評估是否 應對它進一步擴大。optimizer_search_depth值較小會使查詢編輯次數大大減少。例如,若是optimizer_search_depth接 近於查詢中表的數量,對12、13或更多表的查詢極可能須要幾小時甚至幾天的時間來編譯。同時,如 果用optimizer_search_depth等於3或4編輯,對 於同一個查詢,編譯器編譯時間能夠少於1分鐘。若是不能肯定合理的optimizer_search_depth值, 該變量能夠設置爲0,告訴優化器自動肯定該值。
下列大多數測試是在Linux上並用MySQL基準進行 的,可是它們能對其它操做系統和工做負載給出一些指示。
當你用-static連接時,能夠獲得最快的可執行文件。
在Linux上,最好用pgcc和-O3編 譯服務器。爲了用這些選項編譯「sql_yacc.cc」,須要大約200M內 存,由於gcc或pgcc需 要大量的內存使全部函數嵌入(inline)。在配置MySQL時, 也應該設定CXX=gcc以免包括libstdc++庫(它不須要)。 請注意對於某些版本的pgcc,生成的二進制只能運行在真Pentium處 理器上,即便你使用編譯器選項說明你想讓最終的代碼在全部x586-類處理器上工做(例如AMD)。
只經過使用一個較好的編譯器或較好的編譯器選項,在應用中能獲得10-30%的加速。若是你本身編譯SQL服 務器,這特別重要!
當咱們測試Cygnus CodeFusion或Fujitsu編譯器時,兩者均還沒足夠不 出錯來讓MySQL啓用優化進行編譯。
標準MySQL二進制分發編譯爲支持全部字符集。當你本身編譯MySQL時,應只包括將使用 的字符集的支持。經過configure的--with-charset選 項來控制。
這裏是咱們作過的一些測量表:
· 若是你使用pgcc並用-O6編 譯,mysqld服務器比用gcc 2.95.2快11%。
· 若是你動態地連接(沒有-static), 在Linux中結果慢了13%。注意你仍能在客戶應用程序中使用動態連接MySQL庫。 只有服務器對性能是關鍵的。
· 若是你用strip mysqld剝離mysqld二進制,生成的二進制能夠快4%。
· 對於在同一主機上運行的客戶與服務器之間的鏈接,若是你使用TCP/IP而非Unix套 接字文件進行鏈接,結果慢7.5%。(在Unix中,若是你鏈接localhost主 機,MySQL默認使用一個套接字文件)。
· 對於從客戶到服務器的TCP/IP鏈接,從另外一臺主機鏈接一臺遠程服務器要比鏈接同一主機 上的服務器慢8-11%,即便經過100Mb/s以太網進行鏈接。
· 當使用安全鏈接運行咱們的基準測試時(全部數據用內部SSL支 持進行加密),性能比未加密鏈接慢55%。
· 若是你用--with-debug=full編譯,大多數查詢慢20%。 部分查詢時間會很長;例如,MySQL基準的運行要慢35%。若是你使用--with-debug(沒 有=full),速度只降低15%。對於用--with-debug=full編 譯的mysqld版本,能夠用--skip-safemalloc選 項啓動以便在運行時禁用內存檢查。執行速度則接近用--with-debug配置的時候。
· 在Sun UltraSPARC-Iie上,用Forte 5.0編譯的服務器比用gcc 3.2編譯的要快4%。
· 在Sun UltraSPARC-Iie上,用Forte 5.0編譯的32位模式服務器比64位模式服務器要快4%。
· 用gcc 2.95.2編譯帶-mcpu=v8 -Wa的UltraSPARC,使用-xarch=v8plusa選項性能會 提升4%。
· 在Solaris 2.5.1上,在單個處理器上MIT-pthreads比 帶原生線程的Solaris慢8-12%。若是有更大的負載/cpus, 差異應該更大。
· 在Linux-x86上使用gcc編 譯而不用幀指針(-fomit-frame-pointer or -fomit-frame-pointer -ffixed-ebp),可使mysqld快1-4%。
MySQL AB提供的Linux上的二進制MySQL分 發通常用pgcc編譯。咱們必須返回到常規gcc, 由於pgcc中有一個bug,使生成的二進制不能在AMD上 運行。咱們將繼續使用gcc直到該bug被解決。同時,若是你 有一個非AMD機,你能夠用pgcc編譯構建一個更快的二進 制。標準MySQL Linux二進制是經過靜態連接,以使它更快而且更加易於移植。
下面的列表中列出了mysqld服 務器使用內存的一些方法。在適用的地方,給出了內存相關的系統變量名:
· 鍵緩存(變量key_buffer_size)被 全部線程共享;服務器使用的其它緩存則根據須要分配。參見7.5.2節,「調節服務器參數」。
· 每一個鏈接使用具體線程的空間:
o 堆棧(默認64KB,變量thread_stack)
o 鏈接緩存區(變量net_buffer_length)
o 結果緩存區(變量net_buffer_length)
鏈接緩存區和結果緩存區能夠根據須要動態擴充到max_allowed_packet。當某個查詢運行時,也爲當 前查詢字符串分配內存。
· 全部線程共享相同的基本內存。
· 只有壓縮MyISAM表映射到內存。這是由於4GB的32位 內存空間不足以容納大多數大表。當64位地址空間的系統變得愈來愈廣泛後,咱們能夠增長常規的內存映射支持。
· 對錶進行順序掃描的請求將分配一個緩存區(變 量read_buffer_size)。
· 當按任意順序讀取行時(例如,按照排序順序),將分配一個隨機 讀 緩存區(變量read_rnd_buffer_size)以 避免硬盤搜索。
· 全部聯合在一個令牌內完成,而且大多數聯合甚至能夠不用臨時表便可以完成。大多數臨時表是基於內存的(HEAP)表。 具備大的記錄長度的臨時表 (全部列的長度的和)或包含BLOB列的表存儲在硬盤上。
若是某個內部heap(堆積)表大小超過tmp_table_size,MySQL可 以根據須要自動將內存中的heap表改成基於硬盤的MyISAM表。還能夠經過設置mysqld的tmp_table_size選 項來增長臨時表的大小,或設置客戶程序中的SQL選項SQL_BIG_TABLE。參見13.5.3節,「SET語法」。
· 進行排序的大多數請求將分配一個排序緩存區,並根據結果集的大小爲兩個臨時文件分配零。參見A.4.4節,「MySQL將臨時文件儲存在 哪裏」。
· 幾乎全部解析和計算在局部內存中完成。小項目不須要內存,所以避免了普通的慢內存分配和釋放。只爲不指望的大字符串分配內存;使用函數malloc()和free()來 完成。
· 對於每一個打開的MyISAM表,索引文件打開一次;數據文件爲每一個並行運行的線程打開一 次。對於每一個並行線程,將分配一個表結構、一個每一個列的列結構和大小爲3 * N的緩存區(其中N是 最大行的長度,而不是計算BLOB列)。一個BLOB列須要5至8個 字節加上BLOB數據的長度。MyISAM 存儲引擎維護一個額外的行緩存區供內部應用。
· 對於每一個具備BLOB列的表,將對緩存區進行動態擴大以讀入大的BLOB 值。若是你掃描一個表,則分配一個與最大的BLOB值同樣大的緩存區。
· 全部使用的表的句柄結構保存在高速緩存中並以FIFO管理。默認狀況,高速緩存有64個 入口。若是某個表同時被兩個運行的線程使用,高速緩存則爲該提供兩個入口。參見7.4.9節,「MySQL如何打開和關閉表」。
· 當並行執行的線程結束時,FLUSH TABLE語句或mysqladmin flush-table命令能夠當即關閉全部不使用的表並將全部使用中的表標記爲已經關閉。這樣能夠有效釋放大多 數使用中的內存。FLUSH TABLE在關閉全部表以前不返回結果。
ps和其它系統狀態程序能夠報導mysqld使用不少內存。這能夠是在不一樣的內存地址 上的線程棧形成的。例如,Solaris版本的ps將棧間未用的內存算做已用的內存。你能夠經過用swap -s檢查可用交換區來驗證它。咱們用商業內存漏洞探查器測試了mysqld,所以應該有沒有內存漏洞。
當新的客戶鏈接mysqld時,mysqld創 建一個新的線程來處理請求。該線程先檢查是否主機名在主機名緩存中。若是不在,線程試圖解析主機名:
· 若是操做系統支持線程安全gethostbyaddr_r ()和gethostbyname_r()調 用,線程使用它們來執行主機名解析。
· 若是操做系統不支持線程安全調用,線程鎖定一個互斥體並調用gethostbyaddr()和gethostbyname()。 在這種狀況下,在第1個線程解鎖互斥體前,沒有其它線程能夠解析不在主機名緩存中的主機名。
你能夠用--skip-name-resolve選項啓動mysqld來 禁用DNS主機名查找。然而,在這種狀況下,你只可使用MySQL中的受權表中的IP號。
若是你有一個很慢的DNS和許多主機,你能夠經過用--skip-name-resolve禁 用DNS查找或增長HOST_CACHE_SIZE定義(默認值:128)並 從新編譯mysqld來提升性能。
你能夠用--skip-host-cache選項啓動服務器來禁用主機名緩存。要想清除主機名緩存,執行FLUSH HOSTS語句或執行mysqladmin flush-hosts命令。
若是你想要徹底禁止TCP/IP鏈接,用--skip-networking選項啓動mysqld。