Mysql優化建議

承接上篇EXPLAIN學習在發現問題後可結合本篇內容尋找一個合適的解決方案(可優化的地方也就是容易出現問題的地方)

 

1 查詢優化

 

1) 避免 SELECT *,需要什麼數據,就查詢對應的字段。

2) 小表驅動大表,即小的數據集驅動大的數據集。如:以 A,B 兩表爲例,兩表通過 id 字段進行關聯。

 

# 當 B 表的數據集小於 A 表時,用 in 優化 exist;使用 in ,兩表執行順序是先查 B 表,再查 A 表
select * from A where id in (select id from B)

# 當 A 表的數據集小於 B 表時,用 exist 優化 in;使用 exists,兩表執行順序是先查 A 表,再查 B 表
select * from A where exists (select 1 from B where B.id = A.id)

 

3) 一些情況下,可以使用連接代替子查詢,因爲使用 join,MySQL 不會在內存中創建臨時表。

4) 適當添加冗餘字段,減少表關聯。

5) 合理使用索引(下文介紹)。如:爲排序、分組字段建立索引,避免 filesort 的出現。

 

2 索引使用

 

2.1 適合使用索引的場景

 

1) 主鍵自動創建唯一索引

2) 頻繁作爲查詢條件的字段

3) 查詢中與其他表關聯的字段

4) 查詢中排序的字段

5) 查詢中統計或分組字段

 

2.2 不適合使用索引的場景

 

1) 頻繁更新的字段

2) where 條件中用不到的字段

3) 表記錄太少

4) 經常增刪改的表

5) 字段的值的差異性不大或重複性高

 

2.3 索引創建和使用原則

 

1) 單表查詢:哪個列作查詢條件,就在該列創建索引

2) 多表查詢:left join 時,索引添加到右表關聯字段;right join 時,索引添加到左表關聯字段

3) 不要對索引列進行任何操作(計算、函數、類型轉換)

4) 索引列中不要使用 !=,<> 非等於

5) 索引列不要爲空,且不要使用 is null 或 is not null 判斷

6) 索引字段是字符串類型,查詢條件的值要加''單引號,避免底層類型自動轉換

違背上述原則可能會導致索引失效,具體情況需要使用 explain 命令進行查看

 

2.4 索引失效情況

 

除了違背索引創建和使用原則外,如下情況也會導致索引失效:

1) 模糊查詢時,以 % 開頭

2) 使用 or 時,如:字段1(非索引)or 字段2(索引)會導致索引失效。

3) 使用複合索引時,不使用第一個索引列。

 

index(a,b,c) ,以字段 a,b,c 作爲複合索引爲例:

語句 索引是否生效
where a = 1 是,字段 a 索引生效
where a = 1 and b = 2 是,字段 a 和 b 索引生效
where a = 1 and b = 2 and c = 3 是,全部生效
where b = 2 或 where c = 3
where a = 1 and c = 3 字段 a 生效,字段 c 失效
where a = 1 and b > 2 and c = 3 字段 a,b 生效,字段 c 失效
where a = 1 and b like 'xxx%' and c = 3 字段 a,b 生效,字段 c 失效

 

3 數據庫表結構設計

 

3.1 選擇合適的數據類型

 

1) 使用可以存下數據最小的數據類型

2) 使用簡單的數據類型。int 要比 varchar 類型在mysql處理簡單

3) 儘量使用 tinyint、smallint、mediumint 作爲整數類型而非 int

4) 儘可能使用 not null 定義字段,因爲 null 佔用4字節空間

5) 儘量少用 text 類型,非用不可時最好考慮分表

6) 儘量使用 timestamp 而非 datetime

timestamp   datetime
4字節  8字節
默認值爲當前時間 默認值爲null
update語句時,會更新爲當前時間 。把插入的時間從當前時區轉化爲UTC(世界標準時間)進行存儲。查詢時,將其轉換爲客戶端當前時區進行返回  查詢時是原樣輸出
能存儲的時間範圍爲:‘1970-01-01 00:00:01.000000’ 到 ‘2038-01-19 03:14:07.999999’   能存儲的時間範圍爲:‘1000-01-01 00:00:00.000000’ 到 ‘9999-12-31 23:59:59.999999’
   

 

7) 單表不要有太多字段,建議在 20 以內

 

3.2 表的拆分

 

當數據庫中的數據非常大時,查詢優化方案也不能解決查詢速度慢的問題時,我們可以考慮拆分表,讓每張表的數據量變小,從而提高查詢效率。

 

1) 垂直拆分:將表中多個列分開放到不同的表中。例如用戶表中一些字段經常被訪問,將這些字段放在一張表中,另外一些不常用的字段放在另一張表中。
插入數據時,使用事務確保兩張表的數據一致性。

 

2) 水平拆分:按照行進行拆分。例如用戶表中,使用用戶ID,對用戶ID取10的餘數,將用戶數據均勻的分配到0~9的10個用戶表中。查找時也按照這個規則查詢數據。

 

3.3 讀寫分離

 

一般情況下對數據庫而言都是“讀多寫少”。換言之,數據庫的壓力多數是因爲大量的讀取數據的操作造成的。我們可以採用數據庫集羣的方案,使用一個庫作爲主庫,負責寫入數據;其他庫爲從庫,負責讀取數據。這樣可以緩解對數據庫的訪問壓力。

 

四、服務器參數調優

4.1 內存相關

 

sort_buffer_size 排序緩衝區內存大小

join_buffer_size 使用連接緩衝區大小

read_buffer_size 全表掃描時分配的緩衝區大小

 

4.2 IO 相關

 

Innodb_log_file_size 事務日誌大小

Innodb_log_files_in_group 事務日誌個數

Innodb_log_buffer_size 事務日誌緩衝區大小

Innodb_flush_log_at_trx_commit 事務日誌刷新策略 ,其值如下:

0:每秒進行一次 log 寫入 cache,並 flush log 到磁盤

1:在每次事務提交執行 log 寫入 cache,並 flush log 到磁盤

2:每次事務提交,執行 log 數據寫到 cache,每秒執行一次 flush log 到磁盤

 

4.3 安全相關

 

expire_logs_days 指定自動清理 binlog 的天數

max_allowed_packet 控制 MySQL 可以接收的包的大小

skip_name_resolve 禁用 DNS 查找

read_only 禁止非 super 權限用戶寫權限

skip_slave_start 級你用 slave 自動恢復

 

4.4 其他

 

max_connections 控制允許的最大連接數

tmp_table_size 臨時表大小

max_heap_table_size 最大內存表大小

 

參考博客:

https://blog.csdn.net/peter_zcs/article/details/88640649

https://mp.weixin.qq.com/s/MxW_P2ePd6Lqs4wfTuuVFA

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章