MySQL性能管理及架構設計

影響因素

超高QPS和TPS

QPS: 每秒鐘處理查詢量(同時處理SQL的數量)

風險:效率低下的sql

併發量 & CPU使用率

併發量:同一時間處理的請求的數量 和同時連接數不一樣幾千連接數大部分是sleep狀態

風險:

大量的併發 數據庫連接被佔滿(max_connections默認100)

超高的CPU使用率 CPU資源耗盡導致宕機

磁盤IO

注意:

最好不要在主庫上數據庫備份
大型活動前取消備份計劃
風險:

磁盤IO性能突然下降(使用更快的磁盤準備)
其他大量消耗磁盤性能的計劃任務(調整計劃任務,做好磁盤維護)
網卡流量

風險:

網卡IO被佔滿(1000Mb/8≈100MB)
如何避免無法連接數據庫情況:

減少從服務器數量
分級緩存
避免select * 查詢
分離業務網絡或者服務器網絡
其他影響因素

大表

定義:

行數過大,單表超過千萬行 日誌表等沒有更新刪除操作,只有插入或者簡單查詢沒啥問題,但是修改表結構不好
數據文件過大,表數據超過10G
對查詢的影響:

慢查詢 很難在一定時間過濾出需要的數據 大量磁盤IO -> 降低磁盤效率 暗慄
對DDL操作:

建立索引需要很長時間
修改表結構需要長時間鎖表
風險:

MySQL < 5.5 建立索引會鎖表
MySQL >= 5.5 建立索引會引起主從延遲,長時間主從延遲
影響正常的數據操作(數據庫連接數被佔滿)
如何處理(在下文會有說明):

分庫分表

難點:

分表主鍵的選擇
分表後跨分區數據的查詢和統計
大表歷史數據歸檔

難點:

減少對前後端業務的影響
歸檔時間點選擇(定單(年),日誌(周))
如何進行歸檔操作
大事務

什麼是事務:

原子性 -> 不可分割
一致性 -> 數據完整性
隔離性
SQL標準中定義的四種隔離機別(以下隔離性由低到高,併發性由高到低)

未提交讀(髒讀)(READ UNCOMMITED)
已提交讀(默認)(READ COMMITED)
可重複讀(REPEATABLE READ)
可串行化(SERIALIZABLE)

可以通過以下事務指令來驗證已提交讀和可重複讀的區別

begin;

查看隔離級別

show variables like ‘%iso%’;

修改隔離級別

set session tx_isolation=‘read-commited’;
commit;
持久性 -> 一旦提交,永久保存
什麼是大事務:

運行時間長,操作數據多的事務

風險:

鎖定數據太多
大量阻塞和鎖超時
回滾所需時間長
執行時間長,造成主從延遲
如何處理:

避免一次處理太多數據
移出不必要在事務中的SELECT操作
影響性能的幾個方面

服務器硬件

CPU資源和可用內存大小

如何選擇CPU:

更快的CPU 頻率
更多的CPU 數量
CPU密集型應用,當前版本MySQL不支持對同一SQL併發處理,頻率 > 數量

系統的併發量如何,例如Web應用,數量 > 頻率

MySQL版本,5.6之前的對多CPU支持不好,對於5.6包括之後的多CPU處理比較好

32位和64位CPU選擇,這個現在已經不需要選擇了,要注意在64位使用32位服務器版本,因爲最多尋址4G,對MySQL這個單線程數據庫限制很大

內存

常用MySQL存儲引擎

MyISAM

索引緩存在內存中,數據緩存在操作系統

InnoDB

在內存同時緩存數據和索引

注意:增加內存對增加數據庫性能有限,無法無限增加性能

內存的選擇:

內存的主頻,選擇服務器主板支持主頻最高的內存,頻率越高速度越快 儘量使用相同品牌,顆粒,頻率,電壓,校驗技術和型號的內存條,單條容量儘可能大。略大於數據庫所佔磁盤大小最好

磁盤I/O

磁盤的配置和選擇:

傳統機械磁盤:

特點:

使用最多,價格低,最常見,讀寫慢,存儲空間大

過程:

1.移動磁頭到磁盤表面正確位置

2.等待磁盤旋轉,使用所需數據在磁頭下

3.等待磁盤旋轉過去,所有所需數據都被磁頭讀出

1+2(訪問速度) 3(傳輸速度)

選擇:

1.存儲容量

2.傳輸速度

3.訪問時間

4.主軸轉速

5.物理尺寸(越小時間越短,容量小)

使用RAID增強傳統機器硬盤的性能:

定義:

磁盤陣列(Redundant Arrays of Independent Drives,RAID)是由很多塊獨立的磁盤,組合成一個容量巨大的磁盤組,並提供數據冗餘保證數據完整性的技術。

常用RAID級別:

RAID 0是最早出現的RAID模式,即Data Stripping數據分條技術。RAID 0是組建磁盤陣列中最簡單的一種形式,只需要2塊以上的硬盤即可,成本低,可以提高整個磁盤的性能和吞吐量。RAID 0沒有提供冗餘或錯誤修復能力,但實現成本是最低的。
RAID 1稱爲磁盤鏡像,原理是把一個磁盤的數據鏡像到另一個磁盤上,也就是說數據在寫入一塊磁盤的同時,會在另一塊閒置的磁盤上生成鏡像文件,在不影響性能情況下最大限度的保證系統的可靠性和可修復性
RAID5(分佈式奇偶校驗的獨立磁盤結構)。通過分佈式奇偶校驗塊把數據分散到多個磁盤上,這樣如果任何一個盤的數據失效,都可以從奇偶校驗塊中重建,但是如果兩塊磁盤失效,整個卷的數據都無法回覆,gg。(最經濟的磁盤配置)
RAID10(高可靠性與高效磁盤結構)。這種結構無非是一個帶區結構加一個鏡象結構,因爲兩種結構各有優缺點,因此可以相互補充,達到既高效又高速的目的。大家可以結合兩種結構的優點和缺點來理解這種新結構。這種新結構的價格高,可擴充性不好。主要用於數據容量不大,但要求速度和差錯控制的數據庫中。(性能最好的配置)

選擇:

使用固態存儲SSD和PCIe卡:

特點:

相比機械磁盤有更好的隨機讀寫的性能
相比機械磁盤能更好的支持併發
相比機械磁盤更容易損壞
SSD特點:

直接使用SATA接口SATA3.0(6Gbps)SATA2.0(3Gbps)
SATA接口的SSD同樣支持RAID但與機械硬盤的RAID不同
PCI-E SSD特點:

無法使用SATA接口
需要獨特的驅動和配置
價格比SSD貴
性能比SSD好
需要犧牲部分服務器內存和CPU資源
不要使用RAID,成本太高
選擇:

適用於存在大量隨機IO的場景
解決單線程負載的I/O瓶頸
使用網絡存儲NAS和SAN:

SAN特點:

SAN(Storage Area Network)通過光纖連接服務器,通過塊接口訪問,可以當作硬盤使用
大量順序讀寫
隨機讀寫慢
不如本地RAID磁盤
NAS特點:

NAS(Network-Attached Storage)使用網絡連接通過基於文件的協議如NFS或SMB訪問
延遲
選擇:

不適合MySQL數據庫存放數據文件 適合數據庫備份

網絡:

限制:

延遲
帶寬
網絡的質量對性能影響(丟包)
建議:

高性能高寬帶的網絡接口設備和交換機
對多個網卡進行綁定,增強可用性和帶寬
儘可能進行網絡隔離
服務器系統

電腦配置參數(XP默認TCP併發數只有10個) 服務器系統優化參數

系統選擇

Windows
FreeBSD
Solaris(穩定性好,良好的多線程)
Linux
CentOS系統參數優化

內核相關參數(/etc/sysctl.conf)

端口監聽隊列長度

net.core.somaxconn=65535
net.core.netdev_max_backlog=65535
net.ipv4.tcp_max_syn_backlog=65535

加快TCP連接的回收

net.ipv4.tcp_fin_timeout=10
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1

tcp接收和發送緩衝區大小的值

net.core.wmem_default=87380
net.core.wmem_max=16777216
net.core.rmem_default=87380
net.core.rmem_max=16777216

減少失效連接佔用的tcp系統資源的數量

net.ipv4.tcp_keepalive_time=120
net.ipv4.tcp_keepalive_intvl=30
net.ipv4.tcp_keepalive_probes=3

定義單個共享內存段最大值(足夠大)

容納整個innodb緩衝池大小

注意,對於64位Linux,可取最大值爲物理內存-1byte,建議大於物理內存一半,一般取值大於innodb緩衝池大小即可。

kernal.shmmax = 4294967295

系統內存交換分區(磁盤虛擬內存)

保留交換分區很重要,但是要控制何時使用交換分區

這個參數只有在虛擬內存完全滿了才能使用交換分區

vm.swappiness=0
增加資源限制(/etc/security/limit.conf)

以下兩句加到文件末尾

* 對所有用戶有效

soft 當前系統生效設置

hard 系統中所能設定的最大值

nofile 所限制資源是打開文件的最大數目

限制的數量

  • soft nofile 65535
  • hard nofile 65535

65535 保證可以打開足夠多的文件句柄

重啓操作系統生效

磁盤調度策略(/sys/block/devname/queue/scheduler)

cat /sys/block/sda/queue/scheduler

默認的cfq策略

noop anticipatory deadline [cfq]

查看當前系統支持的IO調度算法

dmesg | grep -i scheduler

out

io scheduler noop registered
io scheduler anticipatory registered
io scheduler deadline registered
io scheduler cfq registered (default)

查看當前系統的I/O調度方法:

cat /sys/block/sda/queue/scheduler

out

noop anticipatory deadline [cfq]

臨地更改I/O調度方法:

例如:想更改到noop電梯調度算法:

echo noop > /sys/block/sda/queue/scheduler

想永久的更改I/O調度方法:

修改內核引導參數,加入elevator=調度程序名

vi /boot/grub/menu.lst

更改到如下內容:

kernel /boot/vmlinuz-2.6.18-8.el5 ro root=LABEL=/ elevator=deadline rhgb quiet

需要重啓才能修改調度方法

noop(電梯式調度策略)

NOOP實現了一個簡單的FIFO隊列,它像電梯的工作主法一樣對I/O請求進行組織,當有一個新的請求到來時,它將請求合併到最近的請求之後,以此來保證請求同一介質.NOOP傾向餓死讀而利於寫.NOOP對於閃存設備,RAM,嵌入式系統是最好的選擇.
讀操作需要等待下一次讀操作完成

寫請求通過合併堆積到I/O隊列

deadline(截止時間調度策略)

Deadline確保了在一個截止時間內服務請求,這個截止時間是可調整的,而默認讀期限短於寫期限.這樣就防止了寫操作因爲不能被讀取而餓死的現象.Deadline對數據庫類應用是最好的選擇.
anticipatory(預料I/O調度策略)

本質上與Deadline一樣,但在最後一次讀操作後,要等待6ms,才能繼續進行對其它I/O請求進行調度. 可以從應用程序中預訂一個新的讀請求,改進讀操作的執行,但以一些寫操作爲代價. 它會在每個6ms中插入新的I/O操作,而會將一些小寫入流合併成一個大寫入流,用寫入延時換取最大的寫入吞吐量.AS適合於寫入較多的環境,比如文件服務器 AS對數據庫環境表現很差.
文件系統的選擇

Windows : FAT NTFS(是win服務器的唯一選擇) Linux : EXT3 EXT4 XFS(都有日誌功能)

EXT3/4系統掛在參數(/etc/fstab)

writeback 只有原數據寫入到日誌,innodb有自己的日誌系統,最好,最快

ordered 比writeback稍微慢,一旦崩潰更加安全

journal 不適合innodb

data=writeback | ordered | journal
noatime
nodiratime

/dev/sda1/ext4 noatime,nodiratime,data=writeback 1 1
數據庫存儲引擎的選擇

MySQL體系結構圖

插件式存儲引擎

MyISAM:不支持事務,表級鎖(MySQL5.5之前版本默認存儲引擎)

MyISAM存儲引擎表由MYD和MYI組成

create table ‘tablename’(…)ENGINE=MyISAM DEFAULT CHARSET=utf8
特性:

併發性與鎖級別(讀寫互斥,只讀操作可以接受,讀寫混合操作支持不好)
表損壞修復(不支持事務恢復)
check table [tablename]
repair table [tablename]
MyISAM表支持全文索引,前綴索引
MyISAM表支持數據壓縮(只能讀)
myisampack -b -f(強制) tablename.MYI
限制:

<5.0版本單表最大4G(大表需要修改MAX_Rows和AVG_ROW_LENGTH)
5.0版本支持256TB
場景:

非事務型應用
只讀類應用
空間類應用(支持空間函數,GPS數據等)
InnoDB:事務級存儲引擎,完美支持行級鎖,事務ACID特性(MySQL5.5之後版本默認存儲引擎)

使用表空間存儲:

innodb_file_per_table ON:獨立表空間:tablename.ibd OFF:系統表空間:ibdataX

show variables like ‘innodb_file_per_table’
比較:

系統表空間無法簡單的收縮文件大小
獨立表空間可以通過optimize table命令收縮系統文件
系統表空間會產生IO瓶頸(多個表IO操作)
獨立表空間可以同時向多個文件刷新數據
系統表空間->獨立表空間步驟:

使用mysqldump導出所有數據庫表數據
停止MySQL服務,修改參數,並刪除Innodb相關文件
重啓MySQL服務,重建Innodb系統表空間
重新導入數據
注意下面的系統表空間數據:

Innodb數據字典信息 Undo回滾段

特性:

事務性存儲引擎
完全支持事務的ACID特性
Redo Log和Undo Log(事務)

Redo Log 存儲的是已提交的事務(順序寫入)

Undo Log 存儲的是未提交的事務(隨機讀寫)

show virables like ‘innodb_log_buffer_size’

log 文件數量

show virables like ‘innodb_log_files_in_group’

支持行級鎖
行級鎖可以最大程度的支持併發
行級鎖是由存儲引擎層實現(MySQL完全不瞭解鎖的實現方式)
鎖作用:

管理共享資源的併發訪問
用於實現事務的隔離性
鎖類型:

共享鎖(也稱讀鎖)
獨佔鎖(也稱寫鎖)

測試鎖

開啓事務

begin;

update 數據

進入另一個client進行select操作

因爲事務沒有commit,查到的數據不變

rollback;
鎖粒度:

表級鎖(基本鎖策略,開銷小)
行級鎖

加表級鎖

lock table write;

這時候在另一個client執行查詢就會阻塞

unlock tables;

這時候在另一個client才能執行查詢

阻塞和死鎖
阻塞:不同鎖之間兼容性關係,同一時刻,一個事務需要等待另一個事務的鎖釋放它所佔用資源,產生阻塞。

死鎖:兩個或兩個以上事務在執行過程中相互佔用了對方佔用的資源。

系統可以處理死鎖:資源佔用最少的事務進行回滾操作。

Innodb狀態檢查:

show engine innodb status [\G]
場景:

Innodb適用於大多數OLTP應用
5.7之後支持全文索引和空間函數
CSV存儲引擎

存儲格式:csv文件

特點:

以文本方式存儲在文件中
.csv文件存儲表內容
.csm文件存儲表的元數據如表狀態和數據量
.frm文件存儲表結構信息
所有列不能爲NULL
不支持索引,不適合大表,不適合在線處理
可以對數據文件直接編輯
場景:

數據交換中間表
電子表格->CSV文件->MySQL數據目錄
數據->CSV文件->其他web程序
Archive存儲引擎

特點:

以zlib對錶數據進行壓縮,磁盤I/O更少
數據存儲引擎在ARZ爲後綴的文件中
只支持insert和select操作
支持行級鎖和緩衝區,但是本身不是事務型存儲引擎
只允許在自增ID列建立索引
場景:

日誌和數據採集類應用
Memory存儲引擎

也稱HEAP存儲引擎,所以數據是保存在內存中的
重啓之後數據消失,表重建
IO效率比MyISAM高得多
支持HASH索引和BTree索引
create index inx_1 on ()
create index inx_1 using btree on ()
HASH索引對等值查詢比較快,對範圍查找支持不好;BTree索引對範圍查找支持比較好
所有字段都爲固定長度varchar(10)=char(10)
不支持BLOG和TEXT大字段類型
使用表級鎖(性能不見的比Innodb好)
最大大小由max_heap_table_size參數確定,最大默認16M(需要重建表)
和臨時表區別:

臨時表分爲查詢優化器使用的系統臨時表和create temporary table創建的臨時表,只對當前session可見。
Memory存儲引擎表不是臨時表
系統使用臨時表如果內存未超限制可以使用Memory臨時表,如果超限則需要使用MyISAM臨時表
create temporary table創建的臨時表可以使用任何存儲引擎
場景:

用於查找或映射表,例如郵編地區對應表
用於保存數據分析中產生的中間表
用於緩存週期性聚合數據的結果表
Federated存儲引擎

特點:

提供了訪問遠程MySQL服務器上表的方法
本地不存儲數據,數據全部存放在遠程服務器上
本地需要保存表結構和遠程服務器的連接信息
可以實現SQL Server連接服務器的功能(性能不好)
默認禁止,啓用需要在啓動時增加federated參數
mysql://user_name[:password]@host_name[:port_num]/db_name/tbl_name

查看是否支持

show engine;

配置文件中 federated = 1 重啓服務

在遠程數據庫建表並設置遠程數據庫權限

grant select,update,insert,delete on . to fred_link@‘127.0.0.1’ identified by ‘12345678’;

在本地數據庫建相同的表

create table (…) engine=federated connection=‘mysql://fred_link:[email protected]:3306//’

操作遠程數據庫

場景:

偶爾的統計分析及手工查詢
如何選擇存儲引擎

大多情況選擇innodb

參考條件:

事務(innodb)
備份(innodb在線熱備份)
崩潰恢復(innodb)
存儲引擎特有特性
不需要事務,主要做select和insert操作可以考慮MYISAM
大都insert操作select很少可以考慮Archive存儲引擎
注意:儘量不要混合使用多個存儲引擎
數據庫參數配置

參數很重要,有時候如下圖所示

大多參數配置可以查看我之前寫的 CentOS-7系統初始化以及MySQL配置優化

MySQL獲取配置信息路徑

命令行參數
mysqld_safe --datadir=/data/sql_data
配置文件

查詢默認配置文件讀取順序

mysqld --help --verbose | grep -A 1 ‘Default options’

MySQL配置參數的作用域

全局參數
set global = ;
set @@global. := ;
會話參數
set [session] = ;
set @@session. := ;
內存相關的參數

確定可使用的內存上限
確定MySQL的每個連接使用的內存(分配全部內存)

排序緩衝區大小

sort_buffer_size

連接緩衝區大小

join_buffer_size

對一個表全表掃描時 4K的倍數

read_buffer_size

索引緩衝區大小

read_rnd_buffer_size

以上四個是爲每個線程分配

確定爲OS保留的內存(服務器只布mysql)
如何爲緩衝池分配內存

innodb使用緩衝池大小,重要,緩存索引,緩存數據,鎖,內部數據結構,使用緩衝池延緩寫入

innodb性能嚴重依賴這個參數

總內存 -(每個線程所需要內存*連接數)- 系統保留內存

服務器總內存 75% 以上

Innodb_buffer_pool_size

myisam存儲引擎緩衝池大小

key_buffer_size
select sum(index_length) from information_schema.tables where engine=‘myisam’

全部使用innodb也需要爲這個分配內存,因爲mysql內部表還是使用myisam存儲引擎

I/O相關配置參數

Innodb I/O相關配置

控制單個事務日誌文件大小

Innodb_log_file_size

控制文件個數 (用處不大)

Innodb_log_files_in_group

事務日誌總大小 = 上面兩個參數相乘

日誌緩衝區大小 32M~128M

Innodb_log_buffer_size

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

1[默認]:每次提交每次寫入cache,並flush log到磁盤

2[建議]:每次提交每次寫入cache,每秒flush log到磁盤

Innodb_flush_log_at_trx_commit

避免操作系統和Innodb對數據雙重緩存

通知操作系統不要進行緩存,所有讀寫都通過存儲設備來完成

Innodb_flush_method=O_DIRECT

爲每個表建立單獨表空間

Innodb_file_per_table = 1

雙寫緩存增加數據安全性,防止頁數據損壞寫入之後造成數據損壞

Innodb_doublewrite = 1

MyISAM I/O相關配置

ON:只對在建表時指定了delay_key_write選項的表使用延遲刷新

OFF:每次寫操作後刷新鍵盤緩衝中的髒塊到磁盤

ALL:對所有MYISAM表都使用延遲鍵寫入

delay_key_write
安全相關配置參數

指定自動清理binlog的天數

expire_logs_days

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

max_allowed_packet

禁用DNS查找

skip_name_resolve

確保sysdate()返回確定性日期

防止主從複製不一致

sysdata_is_now

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

保證主從安全性

read_only

禁用Slave自動恢復

skip_slave_start

設置MySQL所使用的SQL模式

sql_mode

sql_mode

strict_trans_tables(如果給定數據不能插入,會中斷事務操作)
no_engine_subtitution(如果指定存儲引擎不可用,不使用默認存儲引擎)
no_zero_date(顧名思義)
no_zero_in_date
only_full_group_by(如果group by中的列不在select語句中,則執行不會成功)
其他常用配置參數

控制MySQL如何向磁盤刷新binlog日誌

設置爲1可以保證每次事務都寫日誌

sync_binlog

控制內存臨時表大小(值保持一致)

tmp_table_size
max_heap_table_size

控制允許最大連接數(默認100建議千以上)

max_connections
數據庫表結構設計和SQL語句

這一節雖然少,但是最重要,如果做的好可能會超過上文的所有優化

庫表結構設計

數據庫設計對性能的影響

過分的反範式化爲表建立太多列
過分的範式化造成太多的表關聯
在OLTP環境中錯誤的使用了不恰當的分區表
使用外鍵保證數據的完整性
尤其是大表儘量減少使用外鍵約束(個人觀點)

總結

性能優化順序

數據庫結構設計和SQL語句優化
數據庫存儲引擎選擇和參數配置
系統選擇和優化
硬件升級
基準測試

定義:基準測試是指通過設計科學的測試方法、測試工具和測試系統,實現對一類測試對象的某項性能指標進行定量的和可對比的測試。可能不關心業務邏輯。
MySQL基準測試目的

建立MySQL服務器的性能基準線
模擬比當前系統更高的負載,以找出系統的擴展瓶頸
測試不同的軟硬件和操作系統配置
證明心的硬件設備配置是否正確
優點:

測試整個系統的性能,包括web服務器、緩存、數據庫等
反映出系統各個組件接口性能問題體現真實性能情況
MySQL基準測試常見指標

單位時間處理事務數(TPS)
單位時間處理查詢數(QPS)
響應時間(平均、最大、最小響應時間,各個時間所佔百分比)
併發量(≠連接數):同時處理查詢請求的數量
計劃和設計基準測試

對整個系統還是某一組件
使用什麼樣的數據
準備基準測試以及數據處理腳本(CPU、IO、網絡流量、狀態和計數器信息等)
#!/bin/bash
INTERVAL=5
PREFIX=/home/imooc/benchmarks/$INTERVAL-sec-status
RUNFILE=/home/imooc/benchmarks/running
echo “1” > $RUNFILE
MYSQL=/usr/local/mysql/bin/mysql
$MYSQL -e “show global variables” >> mysql-variables
while test -e RUNFILE;dofile=RUNFILE; do file=(date +%F_%I)
sleep=$(date +%s.%N | awk ‘{print 5 - ($1 % 5)}’)
sleep sleepts=&quot;sleep ts=&quot;(date +“TS %s.%N %F %T”)"
loadavg=“(uptime)&quot;echo&quot;(uptime)&quot; echo &quot;ts $loadavg” >> PREFIXPREFIX-{file}-status
$MYSQL -e “show global status” >> PREFIXPREFIX-{file}-status &
echo “$ts $loadavg” >> PREFIXPREFIX-{file}-innodbstatus
$MYSQL -e “show engine innodb status” >> PREFIXPREFIX-{file}-innodbstatus &
echo “$ts $loadavg” >> PREFIXPREFIX-{file}-processlist
$MYSQL -e “show full processlist\G” >> PREFIXPREFIX-{file}-processlist &
echo $ts
done
echo Exiting because $RUNFILE does not exists
運行基準測試
保存以及分析基準測試結果
#!/bin/bash
awk ’
BEGIN {
printf “#ts date time load QPS”;
fmt=" %.2f";
}
/^TS/ {
ts = substr($2,1,index($2,".")-1);
load = NF -2;
diff = ts - prev_ts;
printf “\n%s %s %s %s”,ts,$3,4,substr(4,substr(load,1,length($load)-1);
prev_ts=ts;
}
/Queries/{
printf fmt,($2-Queries)/diff;
Queries=KaTeX parse error: Expected 'EOF', got '}' at position 6: 2 }̲ ' "@"
容易忽略的問題

使用生產環境數據時只使用了部分數據
在多用戶場景中,只做單用戶的測試
在單服務器測試分佈式應用
反覆執行統一查詢
基準測試工具

mysqlslap

特點:

模擬服務器負載,並輸出相關統計信息
可以指定也可以自動生成查詢語句
常用參數說明

–auto-generate-sql(系統自動生成SQL腳本測試)
–auto-generate-sql-add-autoincrement(在生成的表中增加自增主鍵)
–auto-generate-sql-load-type(指定測試中使用的查詢類型)
–auto-generate-sql-write-number(指定初始化數據時生成的數據量)
–concurrency(指定併發線程數量)
–engine(指定要測試表的存儲引擎,可以用逗號分割多個存儲引擎)
–no-drop(指定不清理測試數據)
–iterations(指定測試運行次數)
–number-of-queries(指定每個線程查詢數量)
–debug-info(指定輸出額外的內存及CPU統計信息)
–number-int-cols(指定測試表中包含的int類型列的數量)
–number-char-cols(指定測試表中包含的varchar類型列的數量
–create-schema(指定用於執行測試的數據庫名字)
–query(自定義sql腳本)
–only-print(不運行腳本,而是把生成腳本打印出來)
mysqlslap --concurrency=1,50,100,200 --iterations=3 --number-int-cols=5 --number-char-cols=5 --auto-generate-sql --auto-generate-sql-add-autoincrement --engine=myisam,innodb --number-of-queries=10 --create-schema= [–only-print]
sysbench

安裝:

wget https://github.com/akopytov/sysbench/archive/0.5.zip --no-check-certificate
unzip sysbench-0.5.zip
cd sysbench
sudo yum install automake
sudo yum install libtool
./autogen.sh
./configure --with-mysql-includes=/usr/include/mysql/ --with-mysql-libs=/usr/lib64/mysql/
make && make install
常用參數

–test(指定所要執行的測試類型,支持以下參數)
Fileio 文件系統I/O性能測試
cpu cpu性能測試
memory 內存性能測試
Oltp 測試要指定的lua腳本 Lua腳本位於sysbench-0.5/sysbench/tests/db
–mysql-db(指定數據庫名)
–mysql-table-engine(指定存儲引擎)
–olpt-tables-count(執行測試表的數量)
–olpt-table-size(表數據行數)
–num-threads(併發線程數)
–max-time(最大測試時間)
–report-interval(輸出信息時間間隔)
–mysql-user
mysql-password
prepare(準備測試數據)
run(實際測試)
cleanup(清理測試數據)
sysbench --test=cpu --cpu-max-prime=10000 run
sysbench --test=fileio --file-total-size=1G prepare

查看參數

sysbench --test=fileio help
sysbench --test=fileio --num-threads=8 --init-rng=on --file-total-size=1G --file-test-mode=rndrw --report-interval=1 run

測試MySQL腳本

創建一個庫

create database imooc;
grant all privileges on . to xuwenchao@‘localhost’ identified by ‘12345678’;

cd /home/xuwenchao/sysbench/sysbench-0.5/sysbench/tests/db
sysbench --test=./oltp.lua --mysql-table-engine=innodb --oltp-table-size=10000 --mysql-db=imooc --mysql-user=xuwenchao --mysql-password=12345678 --oltp-tables-count=10 --mysql-socket=/usr/local/mysql/data/mysql.sock prepare
數據庫結構優化

目的:

減少數據冗餘
儘量避免數據維護中出現更新,插入和刪除異常(範式化設計)
節約存儲空間
步驟:

需求分析:全面瞭解產品設計的存儲需求
邏輯設計:設計數據邏輯存儲結構
物理設計:根據所使用數據庫特點進行表結構設計
維護優化:根據實際情況對索引存儲結構等進行優化
三範式:重要,但是不總結了,已經學爛了…

關於基本用法這裏就不多說了,關於sql索引和查詢優化在下面總結。

高可用架構設計

MySQL複製功能

作用:

分擔讀負擔
爲高可用、災難恢復、備份提供更多選擇
實現在不同服務器的數據分佈
利用二進制日誌增量進行
不需要太多帶寬
使用基於行的複製進行大批量更改時候會帶來一定帶寬壓力
特別是跨IDC環境複製
實現數據讀取的負載均衡
需要其他組件配合完成
利用DNS輪詢的方式把程序的讀連接到不同的備份數據庫
利用LVS,haproxy這樣的代理方式
非共享架構,同樣的數據分佈在多臺服務器
增加了數據的安全性
利用備份的備庫來減少主庫的負載
複製並不能代替備份
方便進行數據庫高可用架構部署
避免MySQL單點失敗
實現數據庫高可用和故障切換
實現數據庫升級
二進制日誌

MySQL日誌

二進制日誌作用

記錄了所有對MySQL數據庫的修改事件 包括增刪改查事件和對錶結構修改事件,通過binlog命令行工具進行查看

二進制日誌格式

基於段的格式 binlog_format=STATEMENT

優點:

因爲記錄的是事件執行的SQL語句,日誌記錄量相對小,節約磁盤和網絡I/O
注意:只對一條記錄修改或插入,row格式所產生的日誌量小於段產生的
缺點:

必須記錄上下文信息以保證從服務器執行結果和主服務器相同
特定函數如UUID(),user(),非確定性函數無法複製,造成主從服務器數據不一致,中斷複製鏈路

查看日誌格式

show variables like ‘binlog_format’;

刷新日誌

fulsh logs;

查看日誌

show binary logs;

進入系統查看日誌

mysqlbinlog mysql-bin.000002
mysqlbinlog -vv mysql-bin.000002
基於行的格式 binlog_format=ROW

同一SQL語句修改了1000條數據的情況下,基於段的日誌格式只會記錄這個SQL語句,基於行的日誌會有1000條記錄記錄每一行的修改
優點:

避免複製過程中出現的主從不一致的情況,zhu從複製更加安全(只需要應用對行的更改,不需要重新執行SQL語句)
對每一行的修改比基於段的複製高效
缺點:

記錄日誌量大(binlog_row_image=[FULL|MINIMAL|NOBLOB])
混合日誌格式binlog_format=MIXED

特點:

根據sql語句由系統決定基於段和基於行的日誌格式中進行選擇
數量的大小由所執行的SQL語句執行
建議

Binlog_format=mixed
or
Binlog_format=row
Binlog_row_image=minimal
二進制日誌格式對複製的影響

基於SQL語句的複製(SBR)

優點:

日誌量少,節約網絡傳輸I/O
並不強制要求主從數據庫表定義完全一樣
相對基於行復制更加靈活
缺點:

對於非確定事件,無法保證主從複製數據的一致性
對於存儲過程,觸發器,自定義函數進行的修改也可能造成數據不一致
相對基於行復制執行時需要更多的行鎖
基於SQL語句的複製(SBR)

優點:

可以應用任何SQL的複製包括非確定函數,存儲過程等
可以減少數據庫鎖的使用(性能高)
缺點:

主從數據庫表結構必須一致
無法在從服務器單獨執行觸發器
複製的工作方式

主服務器將變更寫入二進制日誌
從服務器讀取主服務器的二進制日誌變更寫入到relay_log中
在從服務器上重放relay_log中的日誌基於SQL段(statement)的日誌是在從服務器上重新執行記錄的SQL
基於行的日誌(row)則是在從庫上直接應用對數據庫行的修改
基於日誌點複製的步驟

在主DB服務器上建立複製賬號
CREATE USER ‘repl’@‘ip’ IDENTIFIED by ‘password’;
GRANT replication SLAVE ON . TO ‘repl’@‘ip’;
配置主數據庫服務器
log_bin = mysql_bin
max_binlog_size = 1000M
binlog_formart = row
expire_logs_day = 7
sync_binlog = 1
server_id = 100 #動態參數,集羣中唯一
配置從數據庫服務器
log_bin = mysql_bin
relay_log = mysqld-relay-bin
server_id = 101
relay_id = mysql-relay-bin
log_slave_update = on #可選 如果變成主服務器必須配置
read_only = on #可選
初始化從服務器數據

innodb推薦

mysqldump --master-data=2 -single-transaction

推薦的熱備份工具

xtrabackup --slave-info
啓動複製鏈路
CHANGE MASTER TO MASTER_HOST = ‘master_host_ip’,
MASTER_USER = ‘repl’,
MASTER_PASSWORD = ‘password’,
MASTER_LOG_FILE = ‘mysql_log_file_name’,
MASTER_LOG_POS = 4;
start slave

備份指令

mysqldump --single-transaction --master-data --triggers --routines --all-databases -uroot -p >> all.sql

在從服務器使用all.sql腳本

mysql -uroot -p < all.sql

MASTER_LOG_FILE和MASTER_LOG_POS在all.sql中獲得

show slave status \G
start slave;

查看複製進程

show processlist;
優點:

是Mysql最早支持的複製技術,bug相對較少
對SQL查詢沒有任何限制
故障處理比較容易
缺點:

故障轉移時重新獲取新主的日誌點信息比較困難
如果偏移量錯誤可能造成遺漏或重複
基於GTID複製

定義:全局事務ID,保證每一個在主上提交的事務在複製集羣中可以生成唯一的ID GTID=source_id:transaction_id
在主DB服務器上建立複製賬號
CREATE USER ‘repl’@‘ip’ IDENTIFIED by ‘password’;
GRANT replication SLAVE ON . TO ‘repl’@‘ip’;
配置主數據庫服務器
bin_log=/usr/local/mysql/log/mysql-bin
server_id=100
gtid_mode=on
enforce-gtid-consiste

啓用上面參數,下面語句不可用

create table … select

log-slave-updates=on
配置從數據庫服務器
server_id=101
relay_log=/usr/local/mysql/log/relay_log
gtid_mode=on
enforce-gtid-consiste

建議

log_slave_update = on #可選 如果變成主服務器必須配置
read_only = on #可選
master_info_repository=TABLE
relay_log_info_repository=TABLE
初始化從服務器數據

innodb推薦

mysqldump --master-data=2 -single-transaction

推薦的熱備份工具

xtrabackup --slave-info

最後記錄備份時最後事務的GTID值

啓動複製鏈路
CHANGE MASTER TO MASTER_HOST = ‘master_host_ip’,
MASTER_USER = ‘repl’,
MASTER_PASSWORD = ‘password’,
MASTER_AUTO_POSITION = 1;
start slave
優點:

可以很方便的進行故障轉移
從庫不會丟失主庫上的任何修改
缺點:

故障處理比較複雜
對執行的SQL有一定限制
選擇複製模式

所使用MySQL版本(<=5.6 不能用GTID)
複製架構以及主從切換方式
所使用高可用管理組件(下文詳細介紹)
對應用的支持程度
MySQL複製拓撲結構

MySQL5.7之前一個從庫只能有一個主庫

MySQL5.7之後一個從庫可以有多個主庫

一主多從複製拓撲

優點:

配置簡單
多個從庫分擔讀負載
用途:

爲不同業務使用不同的從庫
將一臺從庫放到遠程IDC,用作災備恢復
分擔主庫讀負載(但是主庫上的寫仍然會被複制到從庫)
主-主複製拓撲

(ServerId不同) 主主模式

兩個都充當主庫

注意:

產生數據衝突造成複製鏈路中斷,耗費大量時間造成數據丟失
兩個主中操作的表最好分開
使用下面兩個參數控制自增id生成 auto_increment_increment = 2 auto_increment_increment = 1 | 2
主備模式

只有一臺服務器對外提供服務,另一臺處於只讀狀態並只作爲熱備使用

注意:

確保初始數據相同
確保兩臺服務器已經啓動binlog並具有不同的server_id
在兩臺服務器啓用log_slave_updates參數
在初始備庫啓用read_only
擁有備庫的主主複製拓撲

級聯複製

上面的方式可以解決多個從庫對主庫網絡IO和額外負載的影響

MySQL複製性能優化

再看一下這張圖

影響主從延遲的因素:

主庫寫入二進制日誌的時間
優化方案:

控制主庫事務的大小,分割事務大小
二進制日誌傳輸並寫入從庫的時間
優化方案:

使用MIXED日誌格式記錄日誌,設置set binlog_row_image=minimal;
默認情況從庫只有一個SQL線程,主上併發的修改在從庫變成了串行(只有像大促這種活動體現出來慢)
優化方案:

使用多線程複製(5.6之後添加的功能),有時候可能不如單線程

停止鏈路複製

stop slave;
set global slave_parallel_type=‘logical_clock’;
set global slave_parallel_workers=4;

開啓

start slave;
MySQL複製常見問題

由於數據損壞或丟失引起的主從複製錯誤

主庫或從庫意外宕機引起的錯誤
解決方案:

使用跳過二進制日誌事件
注入空事務的方式先恢復中斷的複製鏈路
使用其它方法對比主從服務器數據(下文介紹)
主庫二進制文件損壞
解決方案:

通過change master重新指定(會丟失一些數據)
備庫中繼日誌損壞
在從庫進行數據修改造成主從複製錯誤
解決方案:

設置read_only參數
不唯一的server_id或server_uuid
max_allow_packet設置引起的主從複製錯誤
MySQL複製無法解決的問題

分擔主數據庫寫負載
解決方案:

分庫分表(下文)
自動進行故障轉移以及主從切換
提供讀寫分離功能
關於高可用架構

高可用性:通過儘量縮短日常維護和突發系統崩潰所導致的停機時間提高系統和應用的可用性99999 9999 999 999

影響因素:

服務器磁盤空間耗盡
性能糟糕的SQL
表結構和索引沒有優化
主從數據不一致
認爲操作失敗
如何實現:

避免導致系統不可用因素,減少系統不可用時間
建立完善的監控及報警系統
對備份數據恢復測試
正確配置數據庫環境(注意readonly)
對不需要的數據歸檔和清理(innodb使用獨立表空間)
增加系統冗餘,保證系統不可用時可以儘快恢復
避免存在單點故障

共享存儲本身就會成爲一個單點,如果出問題,恢復起來比較麻煩;DRDB故障轉移時時間長,轉移時不能提供讀服務

利用多寫集羣或NDB集羣(對內存要求高,限制多)來解決單點故障

利用主從複製解決單點問題

主從切換之後如何通知應用新的主服務器IP
如何檢查主服務器可用
如何處理從服務器和主服務器的複製關係
主從切換及數據轉移
MMM架構

MMM架構是主備模式的數據庫架構

需要的資源列表

部署步驟

配置主主複製以及主從同步集羣
安裝主從節點所需支持包
安裝及配置MMM工具集
運行MMM監控服務
測試

1.創建數據庫用戶

2.備份數據庫並同步到其他數據庫

3.配置主從主主複製

前三條前面都有,不多寫了

各個服務器分別安裝mmm

yum search mmm
yum install mysql-mmm-agent.noarch -y

監控節點安裝

yum install mysql-mmm* -y

創建用戶

搭建mmm,具體搭建細節不再贅述,有需要的可以聯繫管理員

優點

使用Perl腳本語言開發及完全開源
提供了讀寫VIP(虛擬IP),使服務器角色變更對前端應用透明
在從服務器出現大量主從延遲,主從鏈路中斷時可以把這臺從服務器讀的虛擬IP漂移到集羣中其他正常服務器。
MMM提供從服務器的延遲監控
MMM提供了主數據庫故障轉移後從服務器對主服務器重新同步功能
很容易對發生故障的主數據庫重新上線
缺點

發佈時間早,不支持MySQL新的複製功能 (只支持基於日誌點的複製)
沒有讀負載均衡的功能
在進行主從切換時,容易造成數據缺失
存在單點故障
MMH架構(Master High Availability)

在MySQL故障切換過程中,MHA能做到0~30秒之內自動完成數據庫的故障切換操作,並且在進行故障切換的過程中,MHA能最大程度上保證數據庫的一致性,以達到真正意義上的高可用。

MHA由兩部分組成:

MHA Manager(管理節點)和MHA
Node(數據節點)
MHA Manager可以獨立部署在一臺獨立的機器上管理多個Master-Slave集羣,也可以部署在一臺Slave上。當Master出現故障時,它可以自動將最新數據的Slave提升爲新的Master,然後將所有其他的Slave重新指向新的Master。整個故障轉移過程對應用程序是完全透明的。
Manager工具包情況如下:

masterha_check_ssh:檢查MHA的SSH配置情況。
masterha_check_repl:檢查MySQL複製狀況。
masterha_manager:啓動MHA。
masterha_check_status:檢測當前MHA運行狀態。
masterha_master_monitor:檢測Master是否宕機。
masterha_master_switch:控制故障轉移(自動或手動)。
masterha_conf_host:添加或刪除配置的server信息。

Node工具包(通常由MHA Manager的腳本觸發,無需人工操作)情況如下:

save_binary_logs:保存和複製Master的binlog日誌。
apply_diff_relay_logs:識別差異的中級日誌時間並將其應用到其他Slave。
filter_mysqlbinlog:去除不必要的ROOLBACK事件(已經廢棄)
purge_relay_logs:清除中繼日誌(不阻塞SQL線程)
MHA工作原理

從宕機崩潰的Master保存二進制日誌事件(binlog event);
識別含有最新更新的Slave;
應用差異的中繼日誌(relay log)到其他Slave;
應用從Master保存的二進制日誌事件;
提升一個Slave爲新的Master;
使其他的Slave連接新的Master進行復制;
MHA配置步驟

配置集羣所有主機的SSH免認證登錄
安裝MHA-node軟件包和MHA-manager軟件包
yum -y install perl-Config-Tiny.noarch per-Time-HiRes.x86_64perl-Parallel-ForkManager perl-Log-Dispatch-Perl.noarchperl-DBD-MySQL ncftp
建立主從複製集羣
配置MHA管理節點
使用masterha_check_ssh和masterha_check_repld對配置進行檢驗
啓動並測試MHA服務
部署步驟

略,有需要聯繫管理員

優點

Perl語言開發的開源工具
支持GTID的複製模式
MHA在進行故障轉移時更不易產生數據丟失
同一個監控節點可以監控多個集羣
加強了數據的安全性
優點

需要編寫腳本或利用第三方工具來實現Vip的配置
MHA啓動後只會對主數據庫進行監控
需要基於SSH的免認證登錄,存在一定安全隱患
沒有提供從服務器的讀負載均衡
讀寫分離與負載均衡

主從複製目的:分擔主庫讀負載

讀寫分離原因:讀既可以在主庫運行又可以在從庫運行,寫操作只能在主庫運行

兩種讀寫分離方式:

程序實現
優點:

由開發人員控制那些查詢在從庫執行,比較靈活
程序直連數據庫,性能耗損較少
缺點:

增加開發量,代碼更復雜
人爲控制容易出現錯誤
中間件實現
mysql-proxy

性能和穩定性不好,不建議使用

maxScale 優點:

由中間件根據查詢語法分析,自動完成讀寫分離
對程序透明,對已有程序不用做任何調整
缺點:

增加了中間層,對查詢效率有損耗
對於延遲敏感業務無法自動在主庫執行
如何實現讀負載均衡

軟件:

LVS
Haproxy
MaxScale
硬件:

F5

最終的高可用架構

數據庫優化

數據庫索引優化

B-Tree索引

B-Tree索引是以B+樹的結構存儲數據

特點:

加快數據的查詢速度
更適合進行範圍查找
使用場景:

全值匹配的查詢
匹配最左前綴的查詢(聯合索引)
匹配列前綴索引
匹配範圍值的查詢
精確匹配左前列並範圍匹配另外一列
只訪問索引的查詢
使用限制:

如果不是按照索引最左列開始查詢,則無法使用索引
使用索引時不能跳過索引鐘的列
Not in和<>操作無法使用索引
如果查詢中某個列的範圍查詢,則其右邊所有列都無法使用索引

Hash索引

特點:

基於Hash表實現,只有查詢條件精確匹配到Hash索引中的所有列時才能使用hash索引
對於Hash索引中的所有列,存儲引擎都會爲每一行計算一個Hash碼,Hash索引中存儲的就是Hash碼
兩次查找,先找到Hash碼,再找對應的行(因爲內存,影響不明顯)
Hash索引無法用於排序
Hash索引不支持部分索引查找也不支持範圍查找
Hash索引中Hash碼的計算可能存在Hash衝突
爲什麼使用索引

索引打打減少了存儲引擎需要掃描的數據量
索引可以幫助我們進行排序以避免使用臨時表
索引可以把隨機IO變爲順序IO(增加磁盤性能)
索引的影響

增加寫操作成本(插入緩存,多次緩存一次寫入)
太多索引增加查詢優化器的選擇時間
索引優化策略

1.索引列上不能使用表達式或函數

糟糕的索引使用

select …
from product
where to_days(out_date) - to_days(current_date) <= 30

修改後的索引使用

select …
from product
where out_date <= date_add(current_date, interval 30 day)

注:out_date是索引列

2.前綴索引和索引列的選擇性

n設置索引大小

注:不同存儲引擎對索引大小有限制

create index index_name on table(col_name(n));
索引的選擇性是不重複索引值和表的記錄數的比值(前綴索引長度選擇儘可能讓選擇的值不同)

3.聯合索引

如何選擇索引列的順序

經常被使用到的列優先
選擇性高的列優先(過濾出更多數據)
寬度小的列優先
4.覆蓋索引

select的數據列只用從索引中就能夠取得

優點:

優化緩存,減少磁盤IO操作(緩存保存更多數據)
減少隨機IO,變隨機IO轉變爲順序IO
可以避免對Innodb主鍵索引的二次查詢
可以避免MyISAM表進行系統調用
不適合建立覆蓋索引的情況:

存儲引擎不支持覆蓋索引
查詢中使用了太多的列
使用了雙%的like查詢
explain select… \G

根據結果中Extra的值using index/using where

判斷是否是從索引查找

select * 無法使用覆蓋索引覆蓋

B-Tree索引使用索引掃描來優化排序

條件:

索引的列順序和Order by子句順序完全一致
索引中所有列的方向(升序降序)和Order by 子句完全一致
Order by 中的字段全部在關聯表的第一張表
B-Tree索引模擬Hash索引優化查詢(Hash索引不能人爲建立)

alter table film add title_md5 varchar(32);
update film set title=md5(title);
create index idx_md5 on film(title_md5);

explain select * from film where title_md5=md5(‘EGG IGBY’) and title=‘EGG IGBY’\G

同時過濾,避免哈希衝突

只能處理全值匹配查找
所使用Hash函數決定索引鍵的大小
利用索引優化鎖

減少鎖定的行數
加快處理速度,加快鎖的釋放

多個事務再沒有name索引的情況執行以下排他鎖語句

select * from where name=‘張三’ for update;
select * from where name=‘李四’ for update;

會產生等待

如果加上索引就不會有等待的問題。

索引的優化和維護

刪除重複和冗餘索引
primary key(id)
unique key(id)
index(id)
建立聯合索引要刪除相關的單個索引
pt-duplicate-key-checker h=127.0.0.1

查找未被使用的索引

索引的名字以及使用次數

select object_schema, object_name, index_name, b.TABLE_ROWS
from performance_schema.table_io_waits_summary_by_index_usage a
join information_schema.tables b
on a.OBJECT_SCHEMA=b.TABLE_SCHEMA and a.OBJECT_NAME=b.TABLE_NAME
where index_name is not null
and count_star = 0
order by object_schema, object_name;

更新索引統計信息以及減少索引碎片

更新索引統計信息

小心會鎖表

innodb 效率更高

analyze table <table_name>

維護表和索引碎片

使用不當會鎖表

optimize table <table_name>

SQL查詢優化

如何獲取有性能問題的SQL

用戶反饋
通過慢查日誌
實時獲取
慢查詢

慢查詢日誌,性能低,主要開銷來自磁盤IO和日誌存儲所需磁盤空間,短時間佔用內存多,默認功能未開啓

啓動慢查詢日誌功能

slow_query_log=on

通過腳本定時開關參數

指定慢查詢日誌存儲路徑文件

slow_query_log_file

指定記錄慢查詢日誌(SQL執行時間)的閾值

通常0.001s比較合適

long_query_time

是否記錄未使用索引的SQL

log_queries_not_using_indexes

set global slow_query_log=on;
慢查詢日誌內容

User@Host: sbtest[sbtest] @ localhost [] Id: 17

Query_time: 0.000233

Lock_time: 0.000120

Rows_sent: 1

Rows_examined: 1

SET timestamp=1564738274;

SELECT…

慢查詢日誌分析工具

mysqldumpslow
彙總除查詢條件外其他完全相同的sql,並將分析結果按照參數中所指定的順序輸出。

-s order(c,t,l,r,at,al,ar)

c : 總次數

t : 總時間

l : 鎖時間

r : 總數據行數

a* : 平均數 at = 總時間 / 總次數

t top 取前top條

mysqldumpslow -s r -t 10 slow-mysql.log
pt-query-digest
pt-query-digest --explain h=127.0.0.1,u=root,p=123456 slow-mysql.log
實時獲取

通過information_schema數據庫下的processlist表 time字段是執行秒數

查詢速度慢的原因

MySQL服務器處理查詢流程

客戶端發送SQL請求到服務器
服務器檢查是否可以在查詢緩存中命中該SQL
服務端進行SQL解析,預處理,再由優化器生成對應執行計劃
根據執行計劃,調用存儲引擎API來查詢數據
將結果返回給客戶端
查詢緩存對sql性能影響

優先檢查這個查詢是否命中查詢緩存中的數據,通過一個對大小寫敏感的哈希查找(全職匹配)實現,必須同一個sql,字段必須相同才能在緩存查找。

注意:對緩存加鎖,降低查詢效率,對讀寫頻繁 的系統不建議使用查詢緩存

設置查詢緩存是否可用

query_cache_type=ON|OFF|DEMAND

DEMAND表示只有在查詢語句中使用SQL_CACHE和SQL_NO_CACHE來控制是否需要緩存

設置查詢緩存內存大小

query_cache_size

設置查詢緩存可用存儲最大值

query_cache_limit

在查詢上加上SQL_NO_CACHE提高效率

設置數據表被鎖是否返回緩存數據

query_cache_wlock_invalidate

設置查詢緩存分配內存塊最小單位

query_cache_min_res_unit
MySQL依照執行計劃和存儲引擎交互階段

服務端進行SQL解析,預處理,再由優化器生成對應執行計劃

語法解析階段通過關鍵字對MySQL語句進行解析,並生成一顆對應的解析樹,MySQL解析器將使用MySQL語法規則驗證和解析查詢
檢查語法是否使用了正確的關鍵字
關鍵字順序是否正確
預處理階段是根據MySQL規則進一步檢查解析樹是否合法
檢查查詢中表和數據列是否存在以及名字或別名是否存在歧義
語法檢查全通過,查詢優化器生成查詢計劃
造成MySQL生成錯誤執行計劃的原因

統計信息不正確
執行計劃中成本估算≠實際執行成本
MySQL服務器不知道那些頁面在內存,那些在磁盤
那些順序讀取,那些隨機讀取
MySQL優化器所認爲的最優可能與你認爲的最優不一樣
MySQL不考慮其他併發查詢,可能影響查詢速度
有時候基於一些固定規則來生成執行計劃
不考慮不受其控制的成本
優化器可優化的SQL類型

重新定義表關聯順序
外連接轉換爲內鏈接
使用等價變換規則
優化count()、min()和max()(根據B-Tree索引優化)
select tables optimized away 優化器已經從執行計劃移除了該表,並以一個常數取而代之
將一個表達式轉化爲常數表達式
子查詢優化
提前終止查詢(limit子句、不成立的結果)

例子

explain select …where id=-1;

id是無符號整形,這個查詢不會讀取數據,直接中止查詢。

對in()條件進行優化
如何查詢處理各個階段所消耗的時間

使用profile

啓動profile, session級別的配置

set profile=1;

查看每個查詢總的時間信息

show profile;

查詢每個階段所消耗時間

show profile for query N;

Sending data一般可以通過索引優化

除了時間信息還有cpu信息

show profile cpu for query 1;

profile官方建議不再使用了,建議使用以下工具

使用performance_schema

啓動所需要的監控

update setup_instruments set enabled=‘YES’ TIMED=‘YES’ where name like ‘stage%’;
update setup_consumers set enabled=‘YES’ where name like ‘events%’;

查詢語句

select a.thread_id ,sql_text,c.event_name,(c.timer_end -c.timer_start) / 1000000000 as ‘duration (ms)’
from events_statements_history_long a join threads b on a.thread_id =b.thread_id
join events_stages_history_long c on c.thread_id=b.thread_id
and c.event_id between a.event_id and a.end_event_id

where b.processlist_id=connection_id() and a.event_name=‘statement/sql/select’

order by a.thread_id,c.event_id;
執行結果:

特定SQL的查詢優化

大表優化

大表數據的修改最好分批處理

DELIMITER USEimmoc USE `immoc`
DROP PROCEDURE IF EXISTS p_delete_rowsKaTeX parse error: Expected 'EOF', got '#' at position 150: … DO #̲ 修改這一行就行 …
DELIMITER;
如何修改大表表結構

對錶中的列的字段類型修改
改變字段寬度會鎖表
無法解決主從延遲問題
解決方法:

從服務器修改後替換主服務器
建立新表

實現上述過程的工具:

pt-online-schema-change

pt-online-schema-change \

修改表結構

–alter=“MODIFY c varchar(150) not null default ‘’”
–user=root --password=123456
D=,t=
–charset=utf8 –-execute
如何優化not in和<>查詢

原SQL

select id
from table01
where id not in (select id from table02);

優化SQL

select a.id
from table01 a
left join table02 b on a.id=b.id
where b.id is null

使用匯總表優化,提前彙總並記錄到表

select count(*)
from product_comment
where pro_id = 123;

優化

create table product_comment_cnt(pro_id int, cnt int);

查詢當前彙總評論數

select count(cnt) from(
select cnt
from product_comment_cnt
where pro_id = 123
UNION ALL
select count(*)
from product_comment
where pro_id = 123
and timestr>DATE(NOW())
) a;
分庫分表

幾種方式

一個實例中的多個數據庫拆分到不同實例

把一個庫中的表分離到不同的數據庫

數據庫分片

對一個庫中相關表進行水平拆分到不同實例的數據庫中

如何選擇分區鍵

分區鍵儘量避免跨分片查詢的發生
分區鍵儘量使各個分片中數據平均
如何存儲無需分片的表

每個分片存儲一份相同數據
保持數據一致 定期檢查
額外節點統一存儲
級聯查詢需要程序進行處理
如何在節點部署分片

每個分片使用單一數據庫,並且數據庫名相同
多個分片表存儲在同一數據庫,表名後加分片號後綴
一個節點部署多個數據庫,每個數據庫包含一個分片
如何分配分片中數據

按分區鍵Hash值取模分配
按分區鍵範圍
利用分區鍵和分片映射表
如何生成全局唯一ID

使用自增id和自增id偏移量
使用全局節點生成id
在用Redis等緩存服務器中創建全局ID
數據庫分片軟件:oneProxyp(使用方式見腳本)

可以進行數據庫分片,讀寫分離和負載均衡等功能。

數據庫監控

具體的關於監控請參考前面的文章
對數據庫可用性監控
對服務器性能監控
對主從複製的監控
對服務器資源監控(磁盤空間)
可用性監控

確認數據庫是否可以通過網絡連接

mysqladmin -umonitor_user -p -h ping
telnet ip port
確認可讀寫

檢查read_only參數是否爲off
建立監控表對錶中數據更行
執行簡單查詢select @@version
監控數據庫連接數

show variables like ‘max_connections’;

查看連接數

show global status like ‘Threads_connected’

監控工具報警

Threads_connected /max_connections > 0.8

數據庫性能監控

記錄性能監控過程中所採集到的數據庫狀態
如何計算QPS和TPS
QPS=(Queries2 - Queries1)/(Uptime_since_flush_status2-Uptime_since_flush_status1)

TPS=((Com_insert2 + Com_update2 + Com_delete2) - (Com_insert1 + Com_update1 + Com_delete1))/(Uptime_since_flush_status2-Uptime_since_flush_status1)
監控數據庫併發請求數量

show global status like ‘Threads_running’

併發請求數量遠小於同一時間連接到數據庫的線程數量

如何監控Innodb阻塞

select b.trx_mysql_thread_id as ‘被阻塞線程’
,b.trx_query as ‘被阻塞SQL’
,c.trx_mysql_thread_id as ‘阻塞線程’
,c.trx_query as ‘阻塞SQL’
,(UNIX_TIMESTAMP()-UNIX_TIMESTAMP(c.trx_started)) as ‘阻塞時間’
from information_schema.innodb_lock_waits a
join information_schema.innodb_trx b
on b.trx_id=a.requesting_trx_id
join information_schema.innodb_trx c
on c.trx_id=a.blocking_trx_id
where (UNIX_TIMESTAMP()-UNIX_TIMESTAMP(c.trx_started)) > 60;

查詢連接號

select connection_id();
主從複製監控

很多延遲不能發現

show slave status;

主上二進制日誌文件名和偏移量

show master status \G

在從上執行

show slave status;
使用多線程的程序對比主上二進制文件偏移量和從上已經傳輸完成的主上二進制文件偏移量是否存在大量延遲

檢查主從複製數據一致

pt-table-checksum

主庫下運行

pt-table-checksum u=dba,p=‘123456’
–databases mysql
–replicate test.checksums

-----《高性能MySQL指南》

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