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