mysql調(diào)優(yōu)要怎么做 mysql數(shù)據(jù)庫(kù)優(yōu)化及sql調(diào)優(yōu)

MySQL性能調(diào)優(yōu) – 你必須了解的15個(gè)重要變量

前言:

創(chuàng)新互聯(lián)公司一直秉承“誠(chéng)信做人,踏實(shí)做事”的原則,不欺瞞客戶,是我們最起碼的底線! 以服務(wù)為基礎(chǔ),以質(zhì)量求生存,以技術(shù)求發(fā)展,成交一個(gè)客戶多一個(gè)朋友!為您提供成都網(wǎng)站建設(shè)、網(wǎng)站制作、成都網(wǎng)頁(yè)設(shè)計(jì)、重慶小程序開(kāi)發(fā)、成都網(wǎng)站開(kāi)發(fā)、成都網(wǎng)站制作、成都軟件開(kāi)發(fā)、成都APP應(yīng)用開(kāi)發(fā)是成都本地專業(yè)的網(wǎng)站建設(shè)和網(wǎng)站設(shè)計(jì)公司,等你一起來(lái)見(jiàn)證!

MYSQL 應(yīng)該是最流行了 WEB 后端數(shù)據(jù)庫(kù)。雖然 NOSQL 最近越來(lái)越多的被提到,但是相信大部分架構(gòu)師還是會(huì)選擇 MYSQL 來(lái)做數(shù)據(jù)存儲(chǔ)。本文作者總結(jié)梳理MySQL性能調(diào)優(yōu)的15個(gè)重要變量,又不足需要補(bǔ)充的還望大佬指出。

1.DEFAULT_STORAGE_ENGINE

如果你已經(jīng)在用MySQL 5.6或者5.7,并且你的數(shù)據(jù)表都是InnoDB,那么表示你已經(jīng)設(shè)置好了。如果沒(méi)有,確保把你的表轉(zhuǎn)換為InnoDB并且設(shè)置default_storage_engine為InnoDB。

為什么?簡(jiǎn)而言之,因?yàn)镮nnoDB是MySQL(包括Percona Server和MariaDB)最好的存儲(chǔ)引擎 – 它支持事務(wù),高并發(fā),有著非常好的性能表現(xiàn)(當(dāng)配置正確時(shí))。這里有詳細(xì)的版本介紹為什么

2.INNODB_BUFFER_POOL_SIZE

這個(gè)是InnoDB最重要變量。實(shí)際上,如果你的主要存儲(chǔ)引擎是InnoDB,那么對(duì)于你,這個(gè)變量對(duì)于MySQL是最重要的。

基本上,innodb_buffer_pool_size指定了MySQL應(yīng)該分配給InnoDB緩沖池多少內(nèi)存,InnoDB緩沖池用來(lái)存儲(chǔ)緩存的數(shù)據(jù),二級(jí)索引,臟數(shù)據(jù)(已經(jīng)被更改但沒(méi)有刷新到硬盤(pán)的數(shù)據(jù))以及各種內(nèi)部結(jié)構(gòu)如自適應(yīng)哈希索引。

根據(jù)經(jīng)驗(yàn),在一個(gè)獨(dú)立的MySQL服務(wù)器應(yīng)該分配給MySQL整個(gè)機(jī)器總內(nèi)存的80%。如果你的MySQL運(yùn)行在一個(gè)共享服務(wù)器,或者你想知道InnoDB緩沖池大小是否正確設(shè)置,詳細(xì)請(qǐng)看這里。

3.INNODB_LOG_FILE_SIZE

InnoDB重做日志文件的設(shè)置在MySQL社區(qū)也叫做事務(wù)日志。直到MySQL 5.6.8事務(wù)日志默認(rèn)值innodb_log_file_size=5M是唯一最大的InnoDB性能殺手。從MySQL 5.6.8開(kāi)始,默認(rèn)值提升到48M,但對(duì)于許多稍繁忙的系統(tǒng),還遠(yuǎn)遠(yuǎn)要低。

根據(jù)經(jīng)驗(yàn),你應(yīng)該設(shè)置的日志大小能在你服務(wù)器繁忙時(shí)能存儲(chǔ)1-2小時(shí)的寫(xiě)入量。如果不想這么麻煩,那么設(shè)置1-2G的大小會(huì)讓你的性能有一個(gè)不錯(cuò)的表現(xiàn)。這個(gè)變量也相當(dāng)重要,更詳細(xì)的介紹請(qǐng)看這里。

當(dāng)然,如果你有大量的大事務(wù)更改,那么,更改比默認(rèn)innodb日志緩沖大小更大的值會(huì)對(duì)你的性能有一定的提高,但是你使用的是autocommit,或者你的事務(wù)更改小于幾k,那還是保持默認(rèn)的值吧。

4.INNODB_FLUSH_LOG_AT_TRX_COMMIT

默認(rèn)下,innodb_flush_log_at_trx_commit設(shè)置為1表示InnoDB在每次事務(wù)提交后立即刷新同步數(shù)據(jù)到硬盤(pán)。如果你使用autocommit,那么你的每一個(gè)INSERT, UPDATE或DELETE語(yǔ)句都是一個(gè)事務(wù)提交。

同步是一個(gè)昂貴的操作(特別是當(dāng)你沒(méi)有寫(xiě)回緩存時(shí)),因?yàn)樗婕皩?duì)硬盤(pán)的實(shí)際同步物理寫(xiě)入。所以如果可能,并不建議使用默認(rèn)值。

兩個(gè)可選的值是0和2:

* 0表示刷新到硬盤(pán),但不同步(提交事務(wù)時(shí)沒(méi)有實(shí)際的IO操作)

* 2表示不刷新和不同步(也沒(méi)有實(shí)際的IO操作)

所以你如果設(shè)置它為0或2,則同步操作每秒執(zhí)行一次。所以明顯的缺點(diǎn)是你可能會(huì)丟失上一秒的提交數(shù)據(jù)。具體來(lái)說(shuō),你的事務(wù)已經(jīng)提交了,但服務(wù)器馬上斷電了,那么你的提交相當(dāng)于沒(méi)有發(fā)生過(guò)。

顯示的,對(duì)于金融機(jī)構(gòu),如銀行,這是無(wú)法忍受的。不過(guò)對(duì)于大多數(shù)網(wǎng)站,可以設(shè)置為innodb_flush_log_at_trx_commit=0|2,即使服務(wù)器最終崩潰也沒(méi)有什么大問(wèn)題。畢竟,僅僅在幾年前有許多網(wǎng)站還是用MyISAM,當(dāng)崩潰時(shí)會(huì)丟失30s的數(shù)據(jù)(更不要提那令人抓狂的慢修復(fù)進(jìn)程)。

那么,0和2之間的實(shí)際區(qū)別是什么?性能明顯的差異是可以忽略不計(jì),因?yàn)樗⑿碌讲僮飨到y(tǒng)緩存的操作是非??斓摹K院苊黠@應(yīng)該設(shè)置為0,萬(wàn)一MySQL崩潰(不是整個(gè)機(jī)器),你不會(huì)丟失任何數(shù)據(jù),因?yàn)閿?shù)據(jù)已經(jīng)在OS緩存,最終還是會(huì)同步到硬盤(pán)的。

5.SYNC_BINLOG

已經(jīng)有大量的文檔寫(xiě)到sync_binlog,以及它和innodb_flush_log_at_trx_commit的關(guān)系,下面我們來(lái)簡(jiǎn)單的介紹下:

a) 如果你的服務(wù)器沒(méi)有設(shè)置從服務(wù)器,而且你不做備份,那么設(shè)置sync_binlog=0將對(duì)性能有好處。

b) 如果你有從服務(wù)器并且做備份,但你不介意當(dāng)主服務(wù)器崩潰時(shí)在二進(jìn)制日志丟失一些事件,那么為了更好的性能還是設(shè)置為sync_binlog=0.

c) 如果你有從服務(wù)器并且備份,你非常在意從服務(wù)器的一致性,以及能及時(shí)恢復(fù)到一個(gè)時(shí)間點(diǎn)(通過(guò)使用最新的一致性備份和二進(jìn)制日志將數(shù)據(jù)庫(kù)恢復(fù)到特定時(shí)間點(diǎn)的能力),那么你應(yīng)該設(shè)置innodb_flush_log_at_trx_commit=1,并且需要認(rèn)真考慮使用sync_binlog=1。

問(wèn)題是sync_binlog=1代價(jià)比較高 – 現(xiàn)在每個(gè)事務(wù)也要同步一次到硬盤(pán)。你可能會(huì)想為什么不把兩次同步合并成一次,想法正確 – 新版本的MySQL(5.6和5.7,MariaDB和Percona Server)已經(jīng)能合并提交,那么在這種情況下sync_binlog=1的操作也不是這么昂貴了,但在舊的mysql版本中仍然會(huì)對(duì)性能有很大影響。

6.INNODB_FLUSH_METHOD

將innodb_flush_method設(shè)置為O_DIRECT以避免雙重緩沖.唯一一種情況你不應(yīng)該使用O_DIRECT是當(dāng)你操作系統(tǒng)不支持時(shí)。但如果你運(yùn)行的是Linux,使用O_DIRECT來(lái)激活直接IO。

不用直接IO,雙重緩沖將會(huì)發(fā)生,因?yàn)樗械臄?shù)據(jù)庫(kù)更改首先會(huì)寫(xiě)入到OS緩存然后才同步到硬盤(pán) – 所以InnoDB緩沖池和OS緩存會(huì)同時(shí)持有一份相同的數(shù)據(jù)。特別是如果你的緩沖池限制為總內(nèi)存的50%,那意味著在寫(xiě)密集的環(huán)境中你可能會(huì)浪費(fèi)高達(dá)50%的內(nèi)存。如果沒(méi)有限制為50%,服務(wù)器可能由于OS緩存的高壓力會(huì)使用到swap。

簡(jiǎn)單地說(shuō),設(shè)置為innodb_flush_method=O_DIRECT。

7.INNODB_BUFFER_POOL_INSTANCES

MySQL 5.5引入了緩沖實(shí)例作為減小內(nèi)部鎖爭(zhēng)用來(lái)提高M(jìn)ySQL吞吐量的手段。

在5.5版本這個(gè)對(duì)提升吞吐量幫助很小,然后在MySQL 5.6版本這個(gè)提升就非常大了,所以在MySQL5.5中你可能會(huì)保守地設(shè)置innodb_buffer_pool_instances=4,在MySQL 5.6和5.7中你可以設(shè)置為8-16個(gè)緩沖池實(shí)例。

你設(shè)置后觀察會(huì)覺(jué)得性能提高不大,但在大多數(shù)高負(fù)載情況下,它應(yīng)該會(huì)有不錯(cuò)的表現(xiàn)。

對(duì)了,不要指望這個(gè)設(shè)置能減少你單個(gè)查詢的響應(yīng)時(shí)間。這個(gè)是在高并發(fā)負(fù)載的服務(wù)器上才看得出區(qū)別。比如多個(gè)線程同時(shí)做許多事情。

8.INNODB_THREAD_CONCURRENCY

InnoDB有一種方法來(lái)控制并行執(zhí)行的線程數(shù) – 我們稱為并發(fā)控制機(jī)制。大部分是由innodb_thread_concurrency值來(lái)控制的。如果設(shè)置為0,并發(fā)控制就關(guān)閉了,因此InnoDB會(huì)立即處理所有進(jìn)來(lái)的請(qǐng)求(盡可能多的)。

在你有32CPU核心且只有4個(gè)請(qǐng)求時(shí)會(huì)沒(méi)什么問(wèn)題。不過(guò)想像下你只有4CPU核心和32個(gè)請(qǐng)求時(shí) – 如果你讓32個(gè)請(qǐng)求同時(shí)處理,你這個(gè)自找麻煩。因?yàn)檫@些32個(gè)請(qǐng)求只有4 CPU核心,顯然地會(huì)比平常慢至少8倍(實(shí)際上是大于8倍),而然這些請(qǐng)求每個(gè)都有自己的外部和內(nèi)部鎖,這有很大可能堆積請(qǐng)求。

下面介紹如何更改這個(gè)變量,在mysql命令行提示符執(zhí)行:

對(duì)于大多數(shù)工作負(fù)載和服務(wù)器,設(shè)置為8是一個(gè)好開(kāi)端,然后你可以根據(jù)服務(wù)器達(dá)到了這個(gè)限制而資源使用率利用不足時(shí)逐漸增加。可以通過(guò)show engine innodb status\G來(lái)查看目前查詢處理情況,查找類似如下行:

9.SKIP_NAME_RESOLVE

這一項(xiàng)不得不提及,因?yàn)槿匀挥泻芏嗳藳](méi)有添加這一項(xiàng)。你應(yīng)該添加skip_name_resolve來(lái)避免連接時(shí)DNS解析。

大多數(shù)情況下你更改這個(gè)會(huì)沒(méi)有什么感覺(jué),因?yàn)榇蠖鄶?shù)情況下DNS服務(wù)器解析會(huì)非???。不過(guò)當(dāng)DNS服務(wù)器失敗時(shí),它會(huì)出現(xiàn)在你服務(wù)器上出現(xiàn)“unauthenticated connections” ,而就是為什么所有的請(qǐng)求都突然開(kāi)始慢下來(lái)了。

所以不要等到這種事情發(fā)生才更改?,F(xiàn)在添加這個(gè)變量并且避免基于主機(jī)名的授權(quán)。

10.INNODB_IO_CAPACITY, INNODB_IO_CAPACITY_MAX

* innodb_io_capacity:用來(lái)當(dāng)刷新臟數(shù)據(jù)時(shí),控制MySQL每秒執(zhí)行的寫(xiě)IO量。

* innodb_io_capacity_max: 在壓力下,控制當(dāng)刷新臟數(shù)據(jù)時(shí)MySQL每秒執(zhí)行的寫(xiě)IO量

首先,這與讀取無(wú)關(guān) – SELECT查詢執(zhí)行的操作。對(duì)于讀操作,MySQL會(huì)盡最大可能處理并返回結(jié)果。至于寫(xiě)操作,MySQL在后臺(tái)會(huì)循環(huán)刷新,在每一個(gè)循環(huán)會(huì)檢查有多少數(shù)據(jù)需要刷新,并且不會(huì)用超過(guò)innodb_io_capacity指定的數(shù)來(lái)做刷新操作。這也包括更改緩沖區(qū)合并(在它們刷新到磁盤(pán)之前,更改緩沖區(qū)是輔助臟頁(yè)存儲(chǔ)的關(guān)鍵)。

第二,我需要解釋一下什么叫“在壓力下”,MySQL中稱為”緊急情況”,是當(dāng)MySQL在后臺(tái)刷新時(shí),它需要刷新一些數(shù)據(jù)為了讓新的寫(xiě)操作進(jìn)來(lái)。然后,MySQL會(huì)用到innodb_io_capacity_max。

那么,應(yīng)該設(shè)置innodb_io_capacity和innodb_io_capacity_max為什么呢?

最好的方法是測(cè)量你的存儲(chǔ)設(shè)置的隨機(jī)寫(xiě)吞吐量,然后給innodb_io_capacity_max設(shè)置為你的設(shè)備能達(dá)到的最大IOPS。innodb_io_capacity就設(shè)置為它的50-75%,特別是你的系統(tǒng)主要是寫(xiě)操作時(shí)。

通常你可以預(yù)測(cè)你的系統(tǒng)的IOPS是多少。例如由8 15k硬盤(pán)組成的RAID10能做大約每秒1000隨機(jī)寫(xiě)操作,所以你可以設(shè)置innodb_io_capacity=600和innodb_io_capacity_max=1000。許多廉價(jià)企業(yè)SSD可以做4,000-10,000 IOPS等。

這個(gè)值設(shè)置得不完美問(wèn)題不大。但是,要注意默認(rèn)的200和400會(huì)限制你的寫(xiě)吞吐量,因此你可能偶爾會(huì)捕捉到刷新進(jìn)程。如果出現(xiàn)這種情況,可能是已經(jīng)達(dá)到你硬盤(pán)的寫(xiě)IO吞吐量,或者這個(gè)值設(shè)置得太小限制了吞吐量。

11.INNODB_STATS_ON_METADATA

如果你跑的是MySQL 5.6或5.7,你不需要更改innodb_stats_on_metadata的默認(rèn)值,因?yàn)樗呀?jīng)設(shè)置正確了。

不過(guò)在MySQL 5.5或5.1,強(qiáng)烈建議關(guān)閉這個(gè)變量 – 如果是開(kāi)啟,像命令show table status會(huì)立即查詢INFORMATION_SCHEMA而不是等幾秒再執(zhí)行,這會(huì)使用到額外的IO操作。

從5.1.32版本開(kāi)始,這個(gè)是動(dòng)態(tài)變量,意味著你不需要重啟MySQL服務(wù)器來(lái)關(guān)閉它。

12.INNODB_BUFFER_POOL_DUMP_AT_SHUTDOWN INNODB_BUFFER_POOL_LOAD_AT_STARTUP

innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup這兩個(gè)變量與性能無(wú)關(guān),不過(guò)如果你偶爾重啟mysql服務(wù)器(如生效配置),那么就有關(guān)。當(dāng)兩個(gè)都激活時(shí),MySQL緩沖池的內(nèi)容(更具體地說(shuō),是緩存頁(yè))在停止MySQL時(shí)存儲(chǔ)到一個(gè)文件。當(dāng)你下次啟動(dòng)MySQL時(shí),它會(huì)在后臺(tái)啟動(dòng)一個(gè)線程來(lái)加載緩沖池的內(nèi)容以提高預(yù)熱速度到3-5倍。

兩件事:

第一,它實(shí)際上沒(méi)有在關(guān)閉時(shí)復(fù)制緩沖池內(nèi)容到文件,僅僅是復(fù)制表空間ID和頁(yè)面ID – 足夠的信息來(lái)定位硬盤(pán)上的頁(yè)面了。然后它就能以大量的順序讀非??焖俚募虞d那些頁(yè)面,而不是需要成千上萬(wàn)的小隨機(jī)讀。

第二,啟動(dòng)時(shí)是在后臺(tái)加載內(nèi)容,因?yàn)镸ySQL不需要等到緩沖池內(nèi)容加載完成再開(kāi)始接受請(qǐng)求(所以看起來(lái)不會(huì)有什么影響)。

從MySQL 5.7.7開(kāi)始,默認(rèn)只有25%的緩沖池頁(yè)面在mysql關(guān)閉時(shí)存儲(chǔ)到文件,但是你可以控制這個(gè)值 – 使用innodb_buffer_pool_dump_pct,建議75-100。

這個(gè)特性從MySQL 5.6才開(kāi)始支持。

13.INNODB_ADAPTIVE_HASH_INDEX_PARTS

如果你運(yùn)行著一個(gè)大量SELECT查詢的MySQL服務(wù)器(并且已經(jīng)盡可能優(yōu)化),那么自適應(yīng)哈希索引將下你的下一個(gè)瓶頸。自適應(yīng)哈希索引是InnoDB內(nèi)部維護(hù)的動(dòng)態(tài)索引,可以提高最常用的查詢模式的性能。這個(gè)特性可以重啟服務(wù)器關(guān)閉,不過(guò)默認(rèn)下在mysql的所有版本開(kāi)啟。

這個(gè)技術(shù)非常復(fù)雜,在大多數(shù)情況下它會(huì)對(duì)大多數(shù)類型的查詢直到加速的作用。不過(guò),當(dāng)你有太多的查詢往數(shù)據(jù)庫(kù),在某一個(gè)點(diǎn)上它會(huì)花過(guò)多的時(shí)間等待AHI鎖和閂鎖。

如果你的是MySQL 5.7,沒(méi)有這個(gè)問(wèn)題 – innodb_adaptive_hash_index_parts默認(rèn)設(shè)置為8,所以自適應(yīng)哈希索引被切割為8個(gè)分區(qū),因?yàn)椴淮嬖谌只コ狻?/p>

不過(guò)在mysql 5.7前的版本,沒(méi)有AHI分區(qū)數(shù)量的控制。換句話說(shuō),有一個(gè)全局互斥鎖來(lái)保護(hù)AHI,可能導(dǎo)致你的select查詢經(jīng)常撞墻。

所以如果你運(yùn)行的是5.1或5.6,并且有大量的select查詢,最簡(jiǎn)單的方案就是切換成同一版本的Percona Server來(lái)激活A(yù)HI分區(qū)。

14.QUERY_CACHE_TYPE

如果人認(rèn)為查詢緩存效果很好,肯定應(yīng)該使用它。好吧,有時(shí)候是有用的。不過(guò)這個(gè)只在你在低負(fù)載時(shí)有用,特別是在低負(fù)載下大多數(shù)是讀取,小量寫(xiě)或者沒(méi)有。

如果是那樣的情況,設(shè)置query_cache_type=ON和query_cache_size=256M就好了。不過(guò)記住不能把256M設(shè)置更高的值了,否則會(huì)由于查詢緩存失效時(shí),導(dǎo)致引起嚴(yán)重的服務(wù)器停頓。

如果你的MySQL服務(wù)器高負(fù)載動(dòng)作,建議設(shè)置query_cache_size=0和query_cache_type=OFF,并重啟服務(wù)器生效。那樣Mysql就會(huì)停止在所有的查詢使用查詢緩存互斥鎖。

15.TABLE_OPEN_CACHE_INSTANCES

從MySQL 5.6.6開(kāi)始,表緩存能分割到多個(gè)分區(qū)。

表緩存用來(lái)存放目前已打開(kāi)表的列表,當(dāng)每一個(gè)表打開(kāi)或關(guān)閉互斥體就被鎖定 – 即使這是一個(gè)隱式臨時(shí)表。使用多個(gè)分區(qū)絕對(duì)減少了潛在的爭(zhēng)用。

從MySQL 5.7.8開(kāi)始,table_open_cache_instances=16是默認(rèn)的配置。

歡迎做Java的工程師朋友們私信我資料免費(fèi)獲取免費(fèi)的Java架構(gòu)學(xué)習(xí)資料(里面有高可用、高并發(fā)、高性能及分布式、Jvm性能調(diào)優(yōu)、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個(gè)知識(shí)點(diǎn)的架構(gòu)資料)

其中覆蓋了互聯(lián)網(wǎng)的方方面面,期間碰到各種產(chǎn)品各種場(chǎng)景下的各種問(wèn)題,很值得大家借鑒和學(xué)習(xí),擴(kuò)展自己的技術(shù)廣度和知識(shí)面。

mysql怎么優(yōu)化,都要怎么做

mysql優(yōu)化是一個(gè)大方向,大的是要分布式、讀寫(xiě)分離,小的是對(duì)sql語(yǔ)句進(jìn)行優(yōu)化。不過(guò)大多問(wèn)的也是對(duì)sql語(yǔ)句優(yōu)化,網(wǎng)上很多資料,我就大體說(shuō)說(shuō)。

1、explain+索引。

在你要查詢的語(yǔ)句前加explain,看下有沒(méi)有用到索引,如果出現(xiàn)type為all的,則說(shuō)明有必要添加下索引。(附多表查詢速度比較:表關(guān)聯(lián)existsin)慢查詢優(yōu)化是一大塊。

2、預(yù)統(tǒng)計(jì)。

很經(jīng)常需要對(duì)歷史的數(shù)據(jù)進(jìn)行過(guò)濾統(tǒng)計(jì)。比如移動(dòng)需要統(tǒng)計(jì)上個(gè)月電話小時(shí)數(shù)超過(guò)N小時(shí)的人,那么如果直接取原始數(shù)據(jù),那將很慢,此時(shí)如果每天晚上凌晨都對(duì)數(shù)據(jù)進(jìn)行預(yù)統(tǒng)計(jì),統(tǒng)計(jì)每個(gè)人每天電話時(shí)數(shù),那再來(lái)過(guò)濾就很快。

3、分表分區(qū)。

分表分區(qū)也是為了提高搜索速度。例如,公交車(chē)的gps行駛記錄,gps每隔15s報(bào)一次,一輛車(chē)一天運(yùn)行12小時(shí),一天就要插入4*60*12條記錄,N輛車(chē)就要再乘,其數(shù)量極大,所以經(jīng)常按月分表,分表里再按上報(bào)時(shí)間做日分區(qū),這樣就達(dá)到很大的優(yōu)化,想查詢某段時(shí)間,mysql很快就可以定位到。

4、表結(jié)構(gòu)。

表結(jié)構(gòu)很重要,經(jīng)常需要多表關(guān)聯(lián)查詢一些字段,有時(shí)可以冗余下放到同一張表。

mysql優(yōu)化很有意思,多去查閱些資料,多去嘗試,對(duì)你有好處的。

超詳細(xì)MySQL數(shù)據(jù)庫(kù)優(yōu)化

數(shù)據(jù)庫(kù)優(yōu)化一方面是找出系統(tǒng)的瓶頸,提高M(jìn)ySQL數(shù)據(jù)庫(kù)的整體性能,而另一方面需要合理的結(jié)構(gòu)設(shè)計(jì)和參數(shù)調(diào)整,以提高用戶的相應(yīng)速度,同時(shí)還要盡可能的節(jié)約系統(tǒng)資源,以便讓系統(tǒng)提供更大的負(fù)荷.

1. 優(yōu)化一覽圖

2. 優(yōu)化

筆者將優(yōu)化分為了兩大類,軟優(yōu)化和硬優(yōu)化,軟優(yōu)化一般是操作數(shù)據(jù)庫(kù)即可,而硬優(yōu)化則是操作服務(wù)器硬件及參數(shù)設(shè)置.

2.1 軟優(yōu)化

2.1.1 查詢語(yǔ)句優(yōu)化

1.首先我們可以用EXPLAIN或DESCRIBE(簡(jiǎn)寫(xiě):DESC)命令分析一條查詢語(yǔ)句的執(zhí)行信息.

2.例:

顯示:

其中會(huì)顯示索引和查詢數(shù)據(jù)讀取數(shù)據(jù)條數(shù)等信息.

2.1.2 優(yōu)化子查詢

在MySQL中,盡量使用JOIN來(lái)代替子查詢.因?yàn)樽硬樵冃枰短撞樵?嵌套查詢時(shí)會(huì)建立一張臨時(shí)表,臨時(shí)表的建立和刪除都會(huì)有較大的系統(tǒng)開(kāi)銷(xiāo),而連接查詢不會(huì)創(chuàng)建臨時(shí)表,因此效率比嵌套子查詢高.

2.1.3 使用索引

索引是提高數(shù)據(jù)庫(kù)查詢速度最重要的方法之一,關(guān)于索引可以參高筆者M(jìn)ySQL數(shù)據(jù)庫(kù)索引一文,介紹比較詳細(xì),此處記錄使用索引的三大注意事項(xiàng):

2.1.4 分解表

對(duì)于字段較多的表,如果某些字段使用頻率較低,此時(shí)應(yīng)當(dāng),將其分離出來(lái)從而形成新的表,

2.1.5 中間表

對(duì)于將大量連接查詢的表可以創(chuàng)建中間表,從而減少在查詢時(shí)造成的連接耗時(shí).

2.1.6 增加冗余字段

類似于創(chuàng)建中間表,增加冗余也是為了減少連接查詢.

2.1.7 分析表,,檢查表,優(yōu)化表

分析表主要是分析表中關(guān)鍵字的分布,檢查表主要是檢查表中是否存在錯(cuò)誤,優(yōu)化表主要是消除刪除或更新造成的表空間浪費(fèi).

1. 分析表: 使用 ANALYZE 關(guān)鍵字,如ANALYZE TABLE user;

2. 檢查表: 使用 CHECK關(guān)鍵字,如CHECK TABLE user [option]

option 只對(duì)MyISAM有效,共五個(gè)參數(shù)值:

3. 優(yōu)化表:使用OPTIMIZE關(guān)鍵字,如OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE user;

LOCAL|NO_WRITE_TO_BINLOG都是表示不寫(xiě)入日志.,優(yōu)化表只對(duì)VARCHAR,BLOB和TEXT有效,通過(guò)OPTIMIZE TABLE語(yǔ)句可以消除文件碎片,在執(zhí)行過(guò)程中會(huì)加上只讀鎖.

2.2 硬優(yōu)化

2.2.1 硬件三件套

1.配置多核心和頻率高的cpu,多核心可以執(zhí)行多個(gè)線程.

2.配置大內(nèi)存,提高內(nèi)存,即可提高緩存區(qū)容量,因此能減少磁盤(pán)I/O時(shí)間,從而提高響應(yīng)速度.

3.配置高速磁盤(pán)或合理分布磁盤(pán):高速磁盤(pán)提高I/O,分布磁盤(pán)能提高并行操作的能力.

2.2.2 優(yōu)化數(shù)據(jù)庫(kù)參數(shù)

優(yōu)化數(shù)據(jù)庫(kù)參數(shù)可以提高資源利用率,從而提高M(jìn)ySQL服務(wù)器性能.MySQL服務(wù)的配置參數(shù)都在my.cnf或my.ini,下面列出性能影響較大的幾個(gè)參數(shù).

2.2.3 分庫(kù)分表

因?yàn)閿?shù)據(jù)庫(kù)壓力過(guò)大,首先一個(gè)問(wèn)題就是高峰期系統(tǒng)性能可能會(huì)降低,因?yàn)閿?shù)據(jù)庫(kù)負(fù)載過(guò)高對(duì)性能會(huì)有影響。另外一個(gè),壓力過(guò)大把你的數(shù)據(jù)庫(kù)給搞掛了怎么辦?所以此時(shí)你必須得對(duì)系統(tǒng)做分庫(kù)分表 + 讀寫(xiě)分離,也就是把一個(gè)庫(kù)拆分為多個(gè)庫(kù),部署在多個(gè)數(shù)據(jù)庫(kù)服務(wù)上,這時(shí)作為主庫(kù)承載寫(xiě)入請(qǐng)求。然后每個(gè)主庫(kù)都掛載至少一個(gè)從庫(kù),由從庫(kù)來(lái)承載讀請(qǐng)求。

2.2.4 緩存集群

如果用戶量越來(lái)越大,此時(shí)你可以不停的加機(jī)器,比如說(shuō)系統(tǒng)層面不停加機(jī)器,就可以承載更高的并發(fā)請(qǐng)求。然后數(shù)據(jù)庫(kù)層面如果寫(xiě)入并發(fā)越來(lái)越高,就擴(kuò)容加數(shù)據(jù)庫(kù)服務(wù)器,通過(guò)分庫(kù)分表是可以支持?jǐn)U容機(jī)器的,如果數(shù)據(jù)庫(kù)層面的讀并發(fā)越來(lái)越高,就擴(kuò)容加更多的從庫(kù)。但是這里有一個(gè)很大的問(wèn)題:數(shù)據(jù)庫(kù)其實(shí)本身不是用來(lái)承載高并發(fā)請(qǐng)求的,所以通常來(lái)說(shuō),數(shù)據(jù)庫(kù)單機(jī)每秒承載的并發(fā)就在幾千的數(shù)量級(jí),而且數(shù)據(jù)庫(kù)使用的機(jī)器都是比較高配置,比較昂貴的機(jī)器,成本很高。如果你就是簡(jiǎn)單的不停的加機(jī)器,其實(shí)是不對(duì)的。所以在高并發(fā)架構(gòu)里通常都有緩存這個(gè)環(huán)節(jié),緩存系統(tǒng)的設(shè)計(jì)就是為了承載高并發(fā)而生。所以單機(jī)承載的并發(fā)量都在每秒幾萬(wàn),甚至每秒數(shù)十萬(wàn),對(duì)高并發(fā)的承載能力比數(shù)據(jù)庫(kù)系統(tǒng)要高出一到兩個(gè)數(shù)量級(jí)。所以你完全可以根據(jù)系統(tǒng)的業(yè)務(wù)特性,對(duì)那種寫(xiě)少讀多的請(qǐng)求,引入緩存集群。具體來(lái)說(shuō),就是在寫(xiě)數(shù)據(jù)庫(kù)的時(shí)候同時(shí)寫(xiě)一份數(shù)據(jù)到緩存集群里,然后用緩存集群來(lái)承載大部分的讀請(qǐng)求。這樣的話,通過(guò)緩存集群,就可以用更少的機(jī)器資源承載更高的并發(fā)。

一個(gè)完整而復(fù)雜的高并發(fā)系統(tǒng)架構(gòu)中,一定會(huì)包含:各種復(fù)雜的自研基礎(chǔ)架構(gòu)系統(tǒng)。各種精妙的架構(gòu)設(shè)計(jì).因此一篇小文頂多具有拋磚引玉的效果,但是數(shù)據(jù)庫(kù)優(yōu)化的思想差不多就這些了.

如何對(duì)mysql服務(wù)器進(jìn)行調(diào)優(yōu)

1、選取最適用的字段屬性

MySQL 可以很好的支持大數(shù)據(jù)量的存取,但是一般說(shuō)來(lái),數(shù)據(jù)庫(kù)中的表越小,在它上面執(zhí)行的查詢也就會(huì)越快。因此,在創(chuàng)建表的時(shí)候,為了獲得更好的性能,我們可以將表中字段的寬度設(shè)得盡可能小。例如,在定義郵政編碼這個(gè)字段時(shí),如果將其設(shè)置為CHAR(255),顯然給數(shù)據(jù)庫(kù)增加了不必要的空間,甚至使用VARCHAR這種類型也是多余的,因?yàn)镃HAR(6)就可以很好的完成任務(wù)了。同樣的,如果可以的話,我們應(yīng)該使用MEDIUMINT而不是BIGIN來(lái)定義整型字段。

另外一個(gè)提高效率的方法是在可能的情況下,應(yīng)該盡量把字段設(shè)置為NOT NULL,這樣在將來(lái)執(zhí)行查詢的時(shí)候,數(shù)據(jù)庫(kù)不用去比較NULL值。

對(duì)于某些文本字段,例如“省份”或者“性別”,我們可以將它們定義為ENUM類型。因?yàn)樵贛ySQL中,ENUM類型被當(dāng)作數(shù)值型數(shù)據(jù)來(lái)處理,而數(shù)值型數(shù)據(jù)被處理起來(lái)的速度要比文本類型快得多。這樣,我們又可以提高數(shù)據(jù)庫(kù)的性能。

2、使用連接(JOIN)來(lái)代替子查詢(Sub-Queries)

MySQL 從4.1開(kāi)始支持SQL的子查詢。這個(gè)技術(shù)可以使用SELECT語(yǔ)句來(lái)創(chuàng)建一個(gè)單列的查詢結(jié)果,然后把這個(gè)結(jié)果作為過(guò)濾條件用在另一個(gè)查詢中。例如,我們要將客戶基本信息表中沒(méi)有任何訂單的客戶刪除掉,就可以利用子查詢先從銷(xiāo)售信息表中將所有發(fā)出訂單的客戶ID取出來(lái),然后將結(jié)果傳遞給主查詢,如下所示:

DELETE FROM customerinfo

WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )

使用子查詢可以一次性的完成很多邏輯上需要多個(gè)步驟才能完成的SQL操作,同時(shí)也可以避免事務(wù)或者表鎖死,并且寫(xiě)起來(lái)也很容易。但是,有些情況下,子查詢可以被更有效率的連接(JOIN).. 替代。例如,假設(shè)我們要將所有沒(méi)有訂單記錄的用戶取出來(lái),可以用下面這個(gè)查詢完成:

SELECT * FROM customerinfo

WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )

如果使用連接(JOIN).. 來(lái)完成這個(gè)查詢工作,速度將會(huì)快很多。尤其是當(dāng)salesinfo表中對(duì)CustomerID建有索引的話,性能將會(huì)更好,查詢?nèi)缦拢?/p>

SELECT * FROM customerinfo

LEFT JOIN salesinfoON customerinfo.CustomerID=salesinfo.

CustomerID

WHERE salesinfo.CustomerID IS NULL

連接(JOIN).. 之所以更有效率一些,是因?yàn)?MySQL不需要在內(nèi)存中創(chuàng)建臨時(shí)表來(lái)完成這個(gè)邏輯上的需要兩個(gè)步驟的查詢工作。

3、使用聯(lián)合(UNION)來(lái)代替手動(dòng)創(chuàng)建的臨時(shí)表

MySQL 從 4.0 的版本開(kāi)始支持 UNION 查詢,它可以把需要使用臨時(shí)表的兩條或更多的 SELECT 查詢合并的一個(gè)查詢中。在客戶端的查詢會(huì)話結(jié)束的時(shí)候,臨時(shí)表會(huì)被自動(dòng)刪除,從而保證數(shù)據(jù)庫(kù)整齊、高效。使用 UNION 來(lái)創(chuàng)建查詢的時(shí)候,我們只需要用 UNION作為關(guān)鍵字把多個(gè) SELECT 語(yǔ)句連接起來(lái)就可以了,要注意的是所有 SELECT 語(yǔ)句中的字段數(shù)目要想同。下面的例子就演示了一個(gè)使用 UNION的查詢。

SELECT Name, Phone FROM client

UNION

SELECT Name, BirthDate FROM author

UNION

SELECT Name, Supplier FROM product

4、事務(wù)

盡管我們可以使用子查詢(Sub-Queries)、連接(JOIN)和聯(lián)合(UNION)來(lái)創(chuàng)建各種各樣的查詢,但不是所有的數(shù)據(jù)庫(kù)操作都可以只用一條或少數(shù)幾條SQL語(yǔ)句就可以完成的。更多的時(shí)候是需要用到一系列的語(yǔ)句來(lái)完成某種工作。但是在這種情況下,當(dāng)這個(gè)語(yǔ)句塊中的某一條語(yǔ)句運(yùn)行出錯(cuò)的時(shí)候,整個(gè)語(yǔ)句塊的操作就會(huì)變得不確定起來(lái)。設(shè)想一下,要把某個(gè)數(shù)據(jù)同時(shí)插入兩個(gè)相關(guān)聯(lián)的表中,可能會(huì)出現(xiàn)這樣的情況:第一個(gè)表中成功更新后,數(shù)據(jù)庫(kù)突然出現(xiàn)意外狀況,造成第二個(gè)表中的操作沒(méi)有完成,這樣,就會(huì)造成數(shù)據(jù)的不完整,甚至?xí)茐臄?shù)據(jù)庫(kù)中的數(shù)據(jù)。要避免這種情況,就應(yīng)該使用事務(wù),它的作用是:要么語(yǔ)句塊中每條語(yǔ)句都操作成功,要么都失敗。換句話說(shuō),就是可以保持?jǐn)?shù)據(jù)庫(kù)中數(shù)據(jù)的一致性和完整性。事物以BEGIN 關(guān)鍵字開(kāi)始,COMMIT關(guān)鍵字結(jié)束。在這之間的一條SQL操作失敗,那么,ROLLBACK命令就可以把數(shù)據(jù)庫(kù)恢復(fù)到BEGIN開(kāi)始之前的狀態(tài)。

BEGIN;

INSERT INTO salesinfo SET CustomerID=14;

UPDATE inventory SET Quantity=11

WHERE item='book';

COMMIT;

事務(wù)的另一個(gè)重要作用是當(dāng)多個(gè)用戶同時(shí)使用相同的數(shù)據(jù)源時(shí),它可以利用鎖定數(shù)據(jù)庫(kù)的方法來(lái)為用戶提供一種安全的訪問(wèn)方式,這樣可以保證用戶的操作不被其它的用戶所干擾。

5、鎖定表

盡管事務(wù)是維護(hù)數(shù)據(jù)庫(kù)完整性的一個(gè)非常好的方法,但卻因?yàn)樗莫?dú)占性,有時(shí)會(huì)影響數(shù)據(jù)庫(kù)的性能,尤其是在很大的應(yīng)用系統(tǒng)中。由于在事務(wù)執(zhí)行的過(guò)程中,數(shù)據(jù)庫(kù)將會(huì)被鎖定,因此其它的用戶請(qǐng)求只能暫時(shí)等待直到該事務(wù)結(jié)束。如果一個(gè)數(shù)據(jù)庫(kù)系統(tǒng)只有少數(shù)幾個(gè)用戶

來(lái)使用,事務(wù)造成的影響不會(huì)成為一個(gè)太大的問(wèn)題;但假設(shè)有成千上萬(wàn)的用戶同時(shí)訪問(wèn)一個(gè)數(shù)據(jù)庫(kù)系統(tǒng),例如訪問(wèn)一個(gè)電子商務(wù)網(wǎng)站,就會(huì)產(chǎn)生比較嚴(yán)重的響應(yīng)延遲。

其實(shí),有些情況下我們可以通過(guò)鎖定表的方法來(lái)獲得更好的性能。下面的例子就用鎖定表的方法來(lái)完成前面一個(gè)例子中事務(wù)的功能。

LOCK TABLE inventory WRITE

SELECT Quantity FROM inventory

WHEREItem='book';

...

UPDATE inventory SET Quantity=11

WHEREItem='book';

UNLOCK TABLES

這里,我們用一個(gè) SELECT 語(yǔ)句取出初始數(shù)據(jù),通過(guò)一些計(jì)算,用 UPDATE 語(yǔ)句將新值更新到表中。包含有 WRITE 關(guān)鍵字的 LOCK TABLE 語(yǔ)句可以保證在 UNLOCK TABLES 命令被執(zhí)行之前,不會(huì)有其它的訪問(wèn)來(lái)對(duì) inventory 進(jìn)行插入、更新或者刪除的操作。

6、使用外鍵

鎖定表的方法可以維護(hù)數(shù)據(jù)的完整性,但是它卻不能保證數(shù)據(jù)的關(guān)聯(lián)性。這個(gè)時(shí)候我們就可以使用外鍵。例如,外鍵可以保證每一條銷(xiāo)售記錄都指向某一個(gè)存在的客戶。在這里,外鍵可以把customerinfo 表中的CustomerID映射到salesinfo表中CustomerID,任何一條沒(méi)有合法CustomerID的記錄都不會(huì)被更新或插入到 salesinfo中。

CREATE TABLE customerinfo

(

CustomerID INT NOT NULL ,

PRIMARY KEY ( CustomerID )

) TYPE = INNODB;

CREATE TABLE salesinfo

(

SalesID INT NOT NULL,

CustomerID INT NOT NULL,

PRIMARY KEY(CustomerID, SalesID),

FOREIGN KEY (CustomerID) REFERENCES customerinfo

(CustomerID) ON DELETECASCADE

) TYPE = INNODB;

注意例子中的參數(shù)“ON DELETE CASCADE”。該參數(shù)保證當(dāng) customerinfo 表中的一條客戶記錄被刪除的時(shí)候,salesinfo 表中所有與該客戶相關(guān)的記錄也會(huì)被自動(dòng)刪除。如果要在 MySQL 中使用外鍵,一定要記住在創(chuàng)建表的時(shí)候?qū)⒈淼念愋投x為事務(wù)安全表 InnoDB類型。該類型不是 MySQL 表的默認(rèn)類型。定義的方法是在 CREATE TABLE 語(yǔ)句中加上 TYPE=INNODB。如例中所示。

7、使用索引

索引是提高數(shù)據(jù)庫(kù)性能的常用方法,它可以令數(shù)據(jù)庫(kù)服務(wù)器以比沒(méi)有索引快得多的速度檢索特定的行,尤其是在查詢語(yǔ)句當(dāng)中包含有MAX(), MIN()和ORDERBY這些命令的時(shí)候,性能提高更為明顯。那該對(duì)哪些字段建立索引呢?一般說(shuō)來(lái),索引應(yīng)建立在那些將用于JOIN, WHERE判斷和ORDER BY排序的字段上。盡量不要對(duì)數(shù)據(jù)庫(kù)中某個(gè)含有大量重復(fù)的值的字段建立索引。對(duì)于一個(gè)ENUM類型的字段來(lái)說(shuō),出現(xiàn)大量重復(fù)值是很有可能的情況,例如 customerinfo中的“province”.. 字段,在這樣的字段上建立索引將不會(huì)有什么幫助;相反,還有可能降低數(shù)據(jù)庫(kù)的性能。我們?cè)趧?chuàng)建表的時(shí)候可以同時(shí)創(chuàng)建合適的索引,也可以使用ALTER TABLE或CREATE INDEX在以后創(chuàng)建索引。此外,MySQL

從版本3.23.23開(kāi)始支持全文索引和搜索。全文索引在 MySQL 中是一個(gè)FULLTEXT類型索引,但僅能用于MyISAM 類型的表。對(duì)于一個(gè)大的數(shù)據(jù)庫(kù),將數(shù)據(jù)裝載到一個(gè)沒(méi)有FULLTEXT索引的表中,然后再使用ALTER TABLE或CREATE INDEX創(chuàng)建索引,將是非常快的。但如果將數(shù)據(jù)裝載到一個(gè)已經(jīng)有FULLTEXT索引的表中,執(zhí)行過(guò)程將會(huì)非常慢。

8、優(yōu)化的查詢語(yǔ)句

絕大多數(shù)情況下,使用索引可以提高查詢的速度,但如果SQL語(yǔ)句使用不恰當(dāng)?shù)脑?,索引將無(wú)法發(fā)揮它應(yīng)有的作用。下面是應(yīng)該注意的幾個(gè)方面。首先,最好是在相同類型的字段間進(jìn)行比較的操作。在MySQL 3.23版之前,這甚至是一個(gè)必須的條件。例如不能將一個(gè)建有索引的INT字段和BIGINT字段進(jìn)行比較;但是作為特殊的情況,在CHAR類型的字段和 VARCHAR類型字段的字段大小相同的時(shí)候,可以將它們進(jìn)行比較。其次,在建有索引的字段上盡量不要使用函數(shù)進(jìn)行操作。

例如,在一個(gè)DATE類型的字段上使用YEAE()函數(shù)時(shí),將會(huì)使索引不能發(fā)揮應(yīng)有的作用。所以,下面的兩個(gè)查詢雖然返回的結(jié)果一樣,但后者要比前者快得多。

SELECT * FROM order WHERE YEAR(OrderDate)2001;

SELECT * FROM order WHERE OrderDate"2001-01-01";

同樣的情形也會(huì)發(fā)生在對(duì)數(shù)值型字段進(jìn)行計(jì)算的時(shí)候:

SELECT * FROM inventory WHERE Amount/724;

SELECT * FROM inventory WHERE Amount24*7;

上面的兩個(gè)查詢也是返回相同的結(jié)果,但后面的查詢將比前面的一個(gè)快很多。第三,在搜索字符型字段時(shí),我們有時(shí)會(huì)使用 LIKE 關(guān)鍵字和通配符,這種做法雖然簡(jiǎn)單,但卻也是以犧牲系統(tǒng)性能為代價(jià)的。例如下面的查詢將會(huì)比較表中的每一條記錄。

SELECT * FROM books

WHERE name like "MySQL%"

但是如果換用下面的查詢,返回的結(jié)果一樣,但速度就要快上很多:

SELECT * FROM books

WHERE name="MySQL"and name"MySQM"

最后,應(yīng)該注意避免在查詢中讓MySQL進(jìn)行自動(dòng)類型轉(zhuǎn)換,因?yàn)檗D(zhuǎn)換過(guò)程也會(huì)使索引變得不起作用。

文章題目:mysql調(diào)優(yōu)要怎么做 mysql數(shù)據(jù)庫(kù)優(yōu)化及sql調(diào)優(yōu)
本文URL:http://muchs.cn/article16/ddccgdg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計(jì)定制網(wǎng)站、云服務(wù)器商城網(wǎng)站、軟件開(kāi)發(fā)、Google

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

網(wǎng)站建設(shè)網(wǎng)站維護(hù)公司