1 常見問題
- 阻塞
- 慢查詢
2 能夠從如下幾個方面入手
- 服務器硬件優化
- 系統配置優化
- 數據庫結構優化
- SQL和索引
一般優化3和4mysql
3 慢查詢日誌
show variables like 'slow_query_log'; # 開啓慢查詢日誌 set global slow_query_log=on; # 查詢慢查詢日誌文件存放的位置 show variables like 'slow_query_log_file'; # 設置慢查詢日誌文件存放的位置 set global slow_query_log_file= '/home/mysql/sql_log/mysql-slow.log' # 設置是否將沒有使用索引的SQL記錄到慢查詢日誌中 set global log_queries_not_using_indexes=on; # 設置是否將查詢事件超過0秒的SQL記錄到慢查詢日誌中,通產設置0.01秒 set global long_query_time=0;
4 實操
4.1 默認不開啓慢查詢日誌
4.2 慢查詢日誌存儲的位置
查詢日誌,這裏我是Docker容器部署MySQL,映射在服務器上
/data/mysql
目錄下 linux
4.3 日誌格式
第一行:執行SQL的主機信息sql
第二行:SQL的執行信息shell
第三行:SQL的執行事件數據庫
第四行:SQL的內容json
5 慢查詢日誌分析工具
5.1 mysqldumpslow(官方工具)
5.1.1 參數解釋
-s 是order的順序 al 平均鎖定時間 ar 平均返回記錄時間 at 平均查詢時間(默認) c 計數 l 鎖定時間 r 返回記錄 t 查詢時間 -t 是top n的意思,即爲返回前面多少條的數據 -g 後邊能夠寫一個正則匹配模式,大小寫不敏感的
5.1.2 基本使用
# 獲得返回記錄集最多的10個SQL。 mysqldumpslow -s r -t 10 /database/mysql/mysql06_slow.log # 獲得訪問次數最多的10個SQL mysqldumpslow -s c -t 10 /database/mysql/mysql06_slow.log # 獲得按照時間排序的前10條裏面含有左鏈接的查詢語句。 mysqldumpslow -s t -t 10 -g 「left join」 /database/mysql/mysql06_slow.log # 另外建議在使用這些命令時結合 | 和more 使用 ,不然有可能出現刷屏的狀況。 mysqldumpslow -s r -t 20 /mysqldata/mysql/mysql06-slow.log | more
5.2 pt-query-digest
5.2.1 快速安裝
wget https://www.percona.com/downloads/percona-toolkit/2.2.16/RPM/percona-toolkit-2.2.16-1.noarch.rpm && yum localinstall -y percona-toolkit-2.2.16-1.noarch.rpm
5.2.2 參數解釋
pt-query-digest [OPTIONS] [FILES] [DSN] --create-review-table 當使用--review參數把分析結果輸出到表中時,若是沒有表就自動建立。 --create-history-table 當使用--history參數把分析結果輸出到表中時,若是沒有表就自動建立。 --filter 對輸入的慢查詢按指定的字符串進行匹配過濾後再進行分析 --limit 限制輸出結果百分比或數量,默認值是20,即將最慢的20條語句輸出,若是是50%則按總響應時間佔比從大到小排序,輸出到總和達到50%位置截止。 --host mysql服務器地址 --user mysql用戶名 --password mysql用戶密碼 --history 將分析結果保存到表中,分析結果比較詳細,下次再使用--history時,若是存在相同的語句,且查詢所在的時間區間和歷史表中的不一樣,則會記錄到數據表中,能夠經過查詢同一CHECKSUM來比較某類型查詢的歷史變化。 --review 將分析結果保存到表中,這個分析只是對查詢條件進行參數化,一個類型的查詢一條記錄,比較簡單。當下次使用--review時,若是存在相同的語句分析,就不會記錄到數據表中。 --output 分析結果輸出類型,值能夠是report(標準分析報告)、slowlog(Mysql slow log)、json、json-anon,通常使用report,以便於閱讀。 --since 從什麼時間開始分析,值爲字符串,能夠是指定的某個」yyyy-mm-dd [hh:mm:ss]」格式的時間點,也能夠是簡單的一個時間值:s(秒)、h(小時)、m(分鐘)、d(天),如12h就表示從12小時前開始統計。 --until 截止時間,配合—since能夠分析一段時間內的慢查詢。
5.2.3 基本使用
# 輸出到文件 pt-query-digest slow-log > slow_log.report # 輸出到數據庫 --create-reviewtable 意思是慢查詢日誌輸出到某一張表中 pt-query-digest slow.log -review h=127.0.0.1,D=test,p=root,P=3306,u=root.t=query_review --create-reviewtable --review-history t= hostname_slow
6 SQL優化
6.1 須要優化的SQL特徵
- 查詢次數多且每次查詢佔用時間長的SQL
- IO大的SQL(SQL中掃描行數越多,IO越大)
- 未命中索引的SQL
6.2 使用explain
查詢SQL的執行計劃
6.2.1 解釋說明
table 顯示這一行數據時關於哪張表的 type 這是重要的列,顯示鏈接使用了那種類型。從最好到最差的鏈接類型爲const,eq_reg,ref,range,index,ALL。const常見於主鍵/惟一索引查找,eq_reg常見於主鍵的範圍查找,ref常見於鏈接查詢,range常見於索引的範圍查找,index常見於索引的掃描,ALL常見於表掃描 possible_keys 顯示可能應用在這張表中的索引。若是爲空,沒有可能的索引。 key 實際使用的索引。若是爲NULL,則沒有使用索引。 key_len 使用的索引長度。在不損失精確性的狀況下,長度越短越好 ref 顯示索引的那一列被使用了,若是可的話,是一個常數 rows MySQL認爲必須檢查的用來返回請求數據的行數
6.3 SQL優化
- 在常常查詢的字段上適當加索引
- 避免子查詢,可優化爲鏈接查詢,注意是否存在一對多關係,可能會出現數據重複
6.4 如何選擇合理的列創建索引
- 在where從句,group by 從句,order by 從句,on 從句中出現的列
- 索引字段越小越好
- 離散度大的列放在聯合索引的前面
例如:緩存
select * from payment where staff_id = 2 and customer_id = 584;
因爲customer_id的離散度更大,因此應該使用index(customer_id,staff_id)安全
6.4.1 如何判斷列的離散程度
select count(distinct customer_id),count(distinct staff_id) from payment
列的惟一值越高,離散程度越大,可選擇性越高。服務器
6.4.2 索引的維護和優化
重複及冗餘索引,重複索引是指相同的列以相同的順序創建的同類型的索引,以下面parmary key
和ID
列上的索引就是重複索引網絡
create table test(id int not null primart key),name vachar(10) not null,title varchar(50) not null,unique(id) ) engine=innodb
使用pt-duplicate-key-checker
工具檢查重複及冗餘索引
pt-duplicate-key-checker -uroot -p'' -h 127.0.0.1
7 數據庫及表結構優化
7.1 選擇合適的數據類型
- 使用能夠存下你的數據的最小的數據類型
- 使用簡單數據類型,int要比varchar類型在MySQL處理上簡單
- 儘可的使用not null 定義字段
- 儘可能少用text類型,非用不可時最好考慮分表
例如
使用bigint
來存儲IP地址,利用INET_ATON()
,INET__NTOA()
兩個函數進行轉換
insert into sessions(ipaddress) values (INET_ATON('127.0.0.1')); select INET__NTOA('127.0.0.1') from sessions;
7.2 範式化和反範式化
7.2.1 範式化
-
第一範式,強調原子性,要求屬性具備原子性,不可再分解
-
第二範式,強調主鍵,要求記錄有惟一標識,即實體的惟一性,級不存在部分依賴
-
第三範式,強調外鍵,要求任何字段不能由其餘字段派生出來,要求字段沒有冗餘,即不存在依賴傳遞
7.2.2 反範式化
爲了查詢效率的考慮,把本來符合第三範式的表適當的增長冗餘,以達到優化查詢效率的目的,反範式化是一種以控件來換時間的操做。
7.3 數據庫結構的優化
7.3.1 表的垂直拆分
把原來一個有不少列的表拆分紅多個表,這解決了表的寬度問題,一般垂直拆分能夠按如下原則進行:
- 把不經常使用的字段單獨存放在一個表中
- 把大字段獨立存在在一個表中
- 把常常一塊兒使用的字段放在一塊兒
7.3.2 表的水平拆分
爲了解決單表的數據量大的問題,水平拆分的表每個表的結構都是徹底一致的
8 系統配置優化
數據庫是基於操做系統的,目前大多數MySQL都是安裝在Linux上,因此對於操做系統的一些參數配置也會影響MySQL的性能,下面列出經常使用的系統配置
8.1 網絡配置方面
修改/etc/sysctl.coonf
文件
# 增長tcp支持的隊列數 net.ip4.tcp_max_syn_backlog=65535 # 減小斷開鏈接時,資源回收 net.ipv4.tcp_max_tw_buckets=8000 net.ipv4.tcp_tw_reuse=1 net.ipv4.tcp_tw_recycle=1 net.ipv4.tcp_fin_timeout=10
打開文件數的限制,可使用ulimit -a查看目錄的各位限制,能夠修改/etc/security/limits.conf
文件,增長如下內容以修改打開文件數量的限制
soft nofile 65335 hard nofile 65535
除此以外最好在MySQL
服務器上關閉iptables
,selinux
等防火牆軟件
8.2 MySQL配置文件
8.2.1 配置文件路徑
Linux:/etc/my.cnf
8.2.2 參數
innodb_buffer_pool_size
:很是重要的參數,用於配置innodb的緩衝池若是數據庫中只有innodb表,則推薦配置量爲總內存的75%
innodb_buffer_pool_instances
:MySQL5.5中新增的參數,能夠控制緩存池的個數,默認狀況下只有一個緩存池
innodb_log_buffer_size
:innodb log緩存的大小,因爲日誌最長每秒鐘就會刷新因此通常不用太大
innodb_flush_log_at_trx_commit
:關鍵參數,對innodb的IO效率影響最大,默認值爲1,能夠取0,1,2三個值,通常建議設置爲2,但若是數據安全性要求比較高則使用默認值1
innodb_read_io_threads
/innodb_write_io_threads
:決定innodb讀寫IO的進程數,默認爲4
innodb_file_per_table
:關鍵參數,控制innodb沒一個表使用獨立的表空間,默認爲OFF,也就是全部表都會創建在共享表空間中
innodb_stats_on_metadata
:決定MySQL在什麼狀況下會刷新innodb表的統計信息
8.2.3 第三方配置工具
Percon Configuration Wizard
9 服務器硬件的優化
9.1 CPU
選擇合適的CPU,單個頻率更快的CPU
- MySQL一些工做只能使用到單核
- MySQL對CPU的核數支持並非越快越好,MySQL5.5使用的服務器不要超過32核
9.2 disk IO優化
經常使用RAID級別簡介
RAID0:也成爲條帶,就是把多個磁盤鏈接成一個硬盤使用,這個級別IO最好
RAID1:也稱爲鏡像,要求至少有兩個磁盤,每組磁盤存儲的數據相同
RAID5:也是把多個(最少3個)硬盤合併成一個邏輯盤使用,數據讀寫時會創建奇偶校驗信息,而且奇偶校驗信息和相對應的數據分別存儲於不一樣的硬盤上。當RAID5的一個磁盤數據發生損壞後,就剩下的數據和相應的奇偶校驗信息去恢復被損壞的數據。
RAID1+0:就是RAID1和RAID0的結合,同時具有兩個級別的優缺點。通常建議數據庫使用這個級別。
SNA和NAT是否適合數據庫
- 經常使用於高可用的解決方案
- 順序讀寫效率很高,可是隨機讀寫不如人意
- 數據庫隨機讀寫效率很高