mysql優化,近期突擊了一下mysql數據庫優化,做自己的一個淺談和收集。有不足之處希望大家指正。
mysql數據庫該怎麼優化?
我們會經常回答添加索引,查詢慢sql。添加緩存。這樣的回答,這樣的回答並不是錯誤的,太籠統不夠具體,沒有細節
下面我做了一個mysql的一個優化流程,要想去做數據庫的優化。需要宏觀的去觀察我們的程序數據庫的峯值瓶頸到底在那裏。
大概優化流程圖:http://on-img.com/chart_image/5a66ab56e4b0332f15428b7e.png
利用腳本去監控mysql的數據庫狀態,分析週期性卡頓、瓶頸。還是不規則性卡頓瓶頸
mysql 監控腳本 https://blog.csdn.net/qq_35809876/article/details/79782130
週期性:
1、監控時間點,排查緩存失效時間,定時任務。
非週期性:
1、開啓慢sql查詢(服務器端,也可以利用阿里druid),找出慢sql,並對語句進行explain 分析,索引是否命中。編寫是否合理
2、查看錶關聯是否設計合理。
3、合理使用緩存減輕數據庫壓力,把不常變動且不重要的 sql 加入緩存中。注意:緩存穿透問題
以上優化的優化思路
=========================================================================================
下面是主要的數據庫的規則。
索引生效原則
B-tree索引 可以理解爲排好序的索引(詳情算法實現,請查詢其他貼子,這方面資料很多)
MySQL官方對索引的定義爲:索引(Index)是幫助MySQL高效獲取數據的數據結構。我們可以簡單理解爲:快速查找排好序的一種數據結構。Mysql索引主要有兩種結構:B+Tree索引和Hash索引。我們平常所說的索引,如果沒有特別指明,一般都是指B樹結構組織的索引(B+Tree索引)。索引如圖所示 :
最外層淺藍色磁盤塊1裏有數據17、35(深藍色)和指針P1、P2、P3(黃色)。P1指針表示小於17的磁盤塊,P2是在17-35之間,P3指向大於35的磁盤塊。真實數據存在於子葉節點也就是最底下的一層3、5、9、10、13......非葉子節點不存儲真實的數據,只存儲指引搜索方向的數據項,如17、35。
查找過程:例如搜索28數據項,首先加載磁盤塊1到內存中,發生一次I/O,用二分查找確定在P2指針。接着發現28在26和30之間,通過P2指針的地址加載磁盤塊3到內存,發生第二次I/O。用同樣的方式找到磁盤塊8,發生第三次I/O。
真實的情況是,上面3層的B+Tree可以表示上百萬的數據,上百萬的數據只發生了三次I/O而不是上百萬次I/O,時間提升是巨大的。
誤區:
已index(a、b、c)爲例
where語句 | 索引是否生效 |
where a = 3 | Y |
where a=3 and b=2 | Y |
where a=3 and b=2 and c=3 | Y |
where a=3 and b>2 and c=3 | N(a\b 能利用索引C不能利用) |
where b=2 and c=3 | N |
where a=1 and b like '%xxxx%' and c=3 | N(a\b能利用索引,c不能) |
where a =1 and c=23 | N(a能利用索引) |
總結:聯合索引 1、必須按照索引順序使用 2、範圍查詢,後面索引無法在生效
hash索引 可以直接在表中快速找到單個結果
特性:
1、hash索引計算出的結果是隨機的,會在磁盤上隨機放置數據
2、無法進行範圍查詢
3、無法利用前綴索引
4、無法優化排序
5、必須回行(回到表中拿出對應行的數據),意思就是說通過索引拿到數據位置,必須回到表中去取數據
重複索引:
一個字段多個索引,數據庫允許這樣操作,但是這樣的索引無效。只會影響表的更新速度
冗餘索引:
是被允許的,這種情況很常見
例:1、index(x.y) index(y.x)
2、index(x) index(x,y)
索引碎片
索引碎片的概念,經常改動數據內容,索引文件和數據文件會產生空洞。從而形成碎片,這樣會讓表的索引效率 和查詢效率降低
解決方案:optimize table 表名 注意:修復表數據和索引碎片重新整理,如果表內容很大,這是一個非常耗資源的過程,請在夜間業務訪問量最低的時候進行或者停服務時進行。如果修改操作比較頻繁,安週期進行整理操作
索引總結:儘量讓查詢sql命中索引,也儘量讓我們查詢字段被索引覆蓋 避免或減少數據庫回行操作
in 子查詢陷阱
create table student id、age ;index(age)
create table person id、name ;index( id)
p.id = s.id
select p.name form persion where id in (select id from student where age >13);
我們正常理解先查詢出學生表年齡大於13的ID 在和person表中的 id 比較查詢出名字
其實不然,可以用explain sql \G 去分析一下 sql 發現persion 表進行了一次全表掃描查詢,student表命中索引
這個sql 執行過程應該是 person進行全表掃描去挨個匹配in 中的內容。
針對上述sql 優化用left join 表關聯查詢
select p.name form student s left join person p on s.id = p.id where s.age>13;
explain 分析 sql 語句
exists 和 group by 比較
exists 要比表關聯 在group by 速度快一些,表關聯 在group by 需要創建一個臨時表在去分組。
而exists 並不需要創建臨時表
count 優化查詢小技巧
select count(*) form table ;非常快因爲表的總數已經被數據庫緩存起來
select count(*) from student where age>9;相對會慢一些
select count(*) from student where age <= 9; 先查詢出較少的數量
select (select count(*) form table ) - (select count(*) from student where age <= 9) as count;
group by 儘量使用在統計 最大數 平均數上。不要使用group by 做數據篩選。
排序
儘量按照某個索引規則執行,排序分爲倆種情況
1、查出來的數據本身就是順序性的。直接在索引上查詢出來的結果就是一個有序的
2、先查出來數據,在根據排序規則重新排序。
知道這倆種情況,我們就知道該如何去做排序優化,爭取讓每次排序都是在索引上查詢出來的結果少一次在排序過程
大數據量分頁優化
select * from pro_order limit 100 ,10;
(等後續添加)
表設計字段類型數據庫查找最快排序 整型、dataTime、varchar