对mysql优化关注_MySQL优化看这篇就对了
我們?cè)诿嬖嚨臅r(shí)候經(jīng)常被問(wèn)到你如何對(duì)數(shù)據(jù)庫(kù)優(yōu)化?動(dòng)不動(dòng)就分庫(kù)分表,但是實(shí)際上有幾個(gè)有分庫(kù)分表的經(jīng)驗(yàn)?zāi)?#xff1f;下面我們將介紹優(yōu)化數(shù)據(jù)庫(kù)的各個(gè)階段。
一、SQL語(yǔ)句優(yōu)化
sql語(yǔ)句的優(yōu)化是我們優(yōu)化數(shù)據(jù)庫(kù)的第一個(gè)階段,也是要最先考慮的方案,成本最低,見(jiàn)效最快的方案。
1.通過(guò)慢查詢(xún)?nèi)罩?#xff0c;找到我們的慢sql
2.通過(guò)EXPLAIN分析執(zhí)行計(jì)劃,使用索引。
慢查詢(xún)?nèi)罩鹃_(kāi)啟
vim /etc/my.cnf
加入如下三行:
slow_query_log=ON //開(kāi)啟慢查詢(xún)
slow_query_log_file=/var/lib/mysql/slow.log //慢查詢(xún)?nèi)罩疚恢?/p>
long_query_time=3 //達(dá)到多少秒的sql就記錄日志,這里是3s
//重啟
systemctl restart mysqld;
執(zhí)行計(jì)劃分析
[圖片上傳失敗...(image-5181eb-1586497621890)]
id:值越大越先執(zhí)行,id相同,從上到下執(zhí)行
key:使用的索引,為空就是不使用
type:
? all:全表掃描
? index:索引全掃描,MySQL遍歷掙個(gè)索引來(lái)查詢(xún)匹配的行,跟all相比就差了個(gè)排序,因?yàn)樗饕緛?lái)就是有序的
? range:索引范圍掃描,常見(jiàn)于、>=、between等操作符
? ref:使用非唯一索引或唯一索引的前綴掃描,返回匹配的單行數(shù)據(jù),這個(gè)就是我們平時(shí)理解的索引查詢(xún)方式B+樹(shù)二分法查詢(xún)
? eq_ref:類(lèi)似ref,區(qū)別就在于使用的索引是唯一索引,簡(jiǎn)單來(lái)說(shuō),就是多表連接中使用primary key或者unique index作為關(guān)聯(lián)條件。
? const/system:單表中最多有一個(gè)匹配行,查詢(xún)起來(lái)非常迅速,常見(jiàn)于根據(jù)primary key或者唯一索引unique index進(jìn)行的單表查詢(xún)
? null:mysql不用訪問(wèn)表或者索引,直接就能夠得到查詢(xún)的結(jié)果,例如select 1+2 as result。
Extra:執(zhí)行情況的說(shuō)明和描述,包含不適合在其他列中顯示但是對(duì)執(zhí)行計(jì)劃非常重要的額外信息,常用取值如下:
? Using index:直接訪問(wèn)索引就取到了數(shù)據(jù),高性能的表現(xiàn)。
? Using where:直接在主鍵索引上過(guò)濾數(shù)據(jù),必帶where子句,而且用不上索引
? Using index condition:先條件過(guò)濾索引,再查數(shù)據(jù),
? Using filesort:使用了外部文件排序 只要見(jiàn)到這個(gè) 就要優(yōu)化掉
? Using temporary:創(chuàng)建了臨時(shí)表來(lái)處理查詢(xún) 只要見(jiàn)到這個(gè) 也要盡量?jī)?yōu)化掉
SQL執(zhí)行順序
[圖片上傳失敗...(image-eec99-1586497621891)]
不是絕對(duì)的有時(shí)候,優(yōu)化器也會(huì)執(zhí)行where過(guò)濾些數(shù)據(jù)在join
優(yōu)化爭(zhēng)議無(wú)數(shù)的count()
count(1)、count()、count(列)在innodb引擎中
? count(1)和count()直接就是統(tǒng)計(jì)主鍵,他們兩個(gè)的效率是一樣的。如果刪除主鍵,他們都走全表掃描。
? 如果count(列)中的字段是索引的話,count(列)和count()一樣快,否則count(列)走全表掃描。
MyiSAM引擎的count(*),因?yàn)镸yiSAM有記錄當(dāng)前的總行數(shù),所以直接取該值就行,快得一逼,但是這個(gè)要在沒(méi)有where條件的情況下,當(dāng)統(tǒng)計(jì)帶有where條件的查詢(xún),那么mysql的count()和其他存儲(chǔ)引擎就沒(méi)有什么不同了
優(yōu)化filesort
當(dāng)我們使用order by進(jìn)行排序的時(shí)候可能會(huì)出現(xiàn)Using filesort,這個(gè)時(shí)候我們就要將這個(gè)優(yōu)化掉
mysql排序方式有2種
? 直接通過(guò)有序索引返回?cái)?shù)據(jù),這種方式的extra顯示為Using Index,不需要額外的排序,操作效率較高。
? 對(duì)返回的數(shù)據(jù)進(jìn)行排序,也就是通常看到的Using filesort,filesort是通過(guò)相應(yīng)的排序算法,將數(shù)據(jù)放在sort_buffer_size系統(tǒng)變量設(shè)置的內(nèi)存排序區(qū)中進(jìn)行排序,如果內(nèi)存裝載不下,它就會(huì)將磁盤(pán)上的數(shù)據(jù)進(jìn)行分塊,再對(duì)各個(gè)數(shù)據(jù)塊進(jìn)行排序,然后將各個(gè)塊合并成有序的結(jié)果集。
SELECT * FROM DB.TB WHERE ID=2222 AND FID IN (9,8,3,13,38,40) ORDER BY INVERSE_DATE LIMIT 0, 5
建立一個(gè)索引 IDX(ID,FID ,INVERSE_DATE)這個(gè)時(shí)候就會(huì)出現(xiàn)Using where; Using filesort。
因?yàn)榻⑺饕臅r(shí)候是id排序后,id相同再排FID,當(dāng)FID有序后,當(dāng)FID相同在排INVERSE_DATE。
這里id是固定,所以我們重新建立一個(gè)索引(ID,INVERSE_DATE),這樣就不會(huì)出現(xiàn)Using filesort。
優(yōu)化limit 分頁(yè)
select * from product limit 10, 20 0.016秒
select * from product limit 100, 20 0.016秒
select * from product limit 1000, 20 0.047秒
select * from product limit 10000, 20 0.094秒
select * from product limit 400000, 20 3.229秒
可以看到隨著條數(shù)的增加,時(shí)間增長(zhǎng)
一般優(yōu)化這個(gè)有兩種
SELECT * FROM product WHERE ID > =(select id from product limit 866613, 1) limit 20 0.2秒
SELECT * FROM product a JOIN (select id from product limit 866613, 20) b ON a.ID = b.id
加一個(gè)參數(shù)來(lái)輔助,標(biāo)記分頁(yè)的開(kāi)始位置:可以是上一次分頁(yè)最大時(shí)間等,這里用id
SELECT * FROM product WHERE id > 800000 LIMIT 20
帶有where的語(yǔ)句
select id from collect where vtype=1 limit 1000,10;
索引應(yīng)該這樣建立(vtype,id),不要建成(id,vtype)
優(yōu)化子查詢(xún)
常見(jiàn)的優(yōu)化方式
? join的時(shí)候使用小表作為主表,驅(qū)動(dòng)表。
select * from a join b on a.id=b.aid where a.create_time>xxx and b.create_time>xxxx
當(dāng)a根據(jù)創(chuàng)建時(shí)間過(guò)濾后的條數(shù)和b根據(jù)過(guò)濾時(shí)間的條數(shù),做比較。。不是直接a,b表做比較
? 不要在列上做運(yùn)算where a-10 = 20 這樣不使用索引,換成 where a=20+10
? 類(lèi)型要一樣 where a=123 如果a是varchar類(lèi)型,這樣就不會(huì)使用索引 換成 where a=‘123’
? IN適合于外表大而內(nèi)表小的情況;EXISTS適合于外表小而內(nèi)表大的情況,這樣效率會(huì)高的
? 能夠用BETWEEN的就不要用IN
? 能夠用DISTINCT的就不用GROUP BY
? 避免使用!=或<>、IS NULL或IS NOT NULL、IN ,NOT IN等這樣的操作符.
? select 列,使用覆蓋索引,減少回表查詢(xún).
一張表最多只存多少數(shù)據(jù),為什么使用B+樹(shù),不使用B樹(shù)
深入理解mysql B+樹(shù)
優(yōu)化器選擇不使用索引
SELECT creator_name,run_time FROM oa_crm_log ORDER BY creator_name limit 10
[圖片上傳失敗...(image-292c4a-1586497621891)]
SELECT creator_name,run_time FROM oa_crm_log ORDER BY creator_name limit 10000
[圖片上傳失敗...(image-7e0c4-1586497621891)]
第一條使用了索引,第二條沒(méi)有使用索引。為什么呢?
這第二條是因?yàn)槲覀冞@個(gè)是非聚集索引,掃描完索引之后還需要,根據(jù)id去隨機(jī)讀取磁盤(pán)(10000次)
而隨機(jī)讀取的性能是很差的。所以sql優(yōu)化器判斷之后使用全表掃描(順序讀取磁盤(pán)性能還是高的)
第一條雖然也是這樣,但是只需要查詢(xún)10條隨機(jī)讀取磁盤(pán)的次數(shù)(10次),相對(duì)比較少,所以sql優(yōu)化器判斷之后使用了索引
優(yōu)化:我們可以使用覆蓋索引,讓我們b+樹(shù)的索引存儲(chǔ)了索引key,這樣我們就不用在回表去查詢(xún)了
建立(creator_name,run_time)的聯(lián)合索引
滿(mǎn)足了使用索引的原則,mysql還是可能會(huì)棄用索引,因?yàn)橛行┎樵?xún)即使使用索引,也會(huì)出現(xiàn)大量的隨機(jī)io,相對(duì)于從數(shù)據(jù)記錄中的順序io開(kāi)銷(xiāo)更大。
join原理 NLJ、BNL、MRR、BKA
顛覆最左原則
t_article表 索引 idnex001(creator_id,updator_id,upator)
select * from t_article where updator_id = 1
select updator_id from t_article where updator_id = 1
這兩條sql會(huì)使用索引嗎?根據(jù)我們理解的mysql最左原則,兩條sql都不會(huì)使用索引。但是事實(shí)卻不是。
第一條,不是使用索引
[圖片上傳失敗...(image-3242e0-1586497621891)]
第二條使用type 為index的索引
[圖片上傳失敗...(image-5d10b6-1586497621891)]
index:這種類(lèi)型表示是mysql會(huì)對(duì)整個(gè)該索引進(jìn)行掃描。要想用到這種類(lèi)型的索引,對(duì)這個(gè)索引并無(wú)特別要求,只要是索引,或者某個(gè)復(fù)合索引的一部分,mysql都可能會(huì)采用index類(lèi)型的方式掃描。但是呢,缺點(diǎn)是效率不高,mysql會(huì)從索引中的第一個(gè)數(shù)據(jù)一個(gè)個(gè)的查找到最后一個(gè)數(shù)據(jù),直到找到符合判斷條件的某個(gè)索引。
所以上面兩條都滿(mǎn)足使用index的原則。
第一條沒(méi)有使用索引是因?yàn)槲覀儾樵?xún)select * 的話,輔助索引還需要到主鍵索引進(jìn)行隨機(jī)查詢(xún)。。優(yōu)化器認(rèn)為順序掃描更優(yōu),所以沒(méi)有使用索引
第二條就不需要在要主鍵索引進(jìn)行隨機(jī)查詢(xún),所以使用了index類(lèi)型的索引。
mysql 聚簇與非聚簇索引
二、引入緩存
在sql優(yōu)化搞不定的時(shí)候,我們才需要考慮引入緩存,但我們要知道當(dāng)引入緩存的時(shí)候系統(tǒng)的復(fù)雜性增加了,同時(shí)也會(huì)引入很多問(wèn)題,比如數(shù)據(jù)庫(kù)和緩存一致性問(wèn)題等等。
這里很多問(wèn)題都寫(xiě)過(guò)了。。參照下面各個(gè)鏈接
mybatis的二級(jí)緩存、ehcache本地緩存
這個(gè)比較簡(jiǎn)單省略
redis的分布式緩存
Redis安裝及持久化
數(shù)據(jù)庫(kù)和緩存不一致的方案
刪除緩存還是更新緩存
先操作緩存(刪除緩存)還是數(shù)據(jù)庫(kù)
緩存穿透、擊穿、雪崩
緩存重建沖突(分布式鎖)、使用雙層nginx提高緩存命中
三、讀寫(xiě)分離
數(shù)據(jù)庫(kù)主從不一致
從庫(kù)和緩存不一致(雙淘汰方案)
四、分區(qū)表
五、垂直拆分
六、水平拆分
總結(jié)
以上是生活随笔為你收集整理的对mysql优化关注_MySQL优化看这篇就对了的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 怎么在Steam跨区购买游戏?
- 下一篇: centos6.5 yum安装mysql