mysql***能調優
使用memcache,redis作爲緩存,使用mariaDB 的XtraDB引擎
數據庫垂直切分,水平切分,主從複製,讀寫分離
服務化+消息中間件,實現異步,解耦,並行,寫合併....
降級
1,硬件
採用高***價比PC服務器,大內存,強勁CPU
採用高***能PCI-E Flash卡作爲cache, 提高系統的IO***能
充分利用系統各部件的cache, 大膽採用新技術
充分考慮容災,在各個層面考慮數據的安全***
Cache分配:
MySQL內部cache
匿名頁面/文件頁面
Flashcache 混合存儲
Raid卡內部cache
數據訪問規律導向,隨機數據和順序數據儘量分離
儘量提高IO的利用率,減少無謂的IO能力浪費
在安全***的前提下,儘可能的利用好系統各個層次cache
2,mysql
使用獨享表空間不用考慮 innodb_file_per_table
關閉自動提交
設置隔離級別爲讀提交
set tx_isolation='read-committed';
關閉自動提交 set autocommit=off;
啓動事務 start transaction;
有的觀點是這樣的 需要使用AUTOCOMMIT=1,
否則CPU就會被輕易地浪費在啓動事務、提交事務上,
你會實際上損失系統的整體***能。
開啓binlog帶來的***能開銷 ,是否需要開啓。其實從的可以不用的,如果要開啓
innodb_flush_log_at_trx_commit = 0或1或2 2表示事務提交才fiush log
用一塊單獨的盤放二進制日誌,可以提升***能,也能保證數據安全
限制最大鏈接數 max_connections = #
是否需要開啓查詢緩存 query_cache_size = #
qcache_hits/(com_select+qcache_hits)
命中和寫入的比率,即Qcache_hits/Qcache_inserts的值,此比值如果能大於3:1,
則表明緩存是有效的
配置合適的緩存塊大小
緩存塊大小計算query_cache_min_res_unit
一般用已使用的緩存空間除以緩存條數
(query_cache_size-qcache_free_memory)/Qcache_queries_in_cache
innodb_buffer_pool_size = 72G 這個參數是innodb索引和數據公用的buffer當然是越大越好
官方建議物理內存的80%
skip-name-resolve 不進行DNS反解,網絡最慢一個就有DNS解析
sync_binlog=n,當每進行 n 次事務提交之後,MySQL 將進行一次 fsync 之類的磁盤同步指令來
將 binlog_cache 中的數據強制寫入磁盤,爲0表示由文件系統自己決定。在高併發的事務中
爲0和爲1的***能有5倍的差距,數據安全沒保證。
slow_query_log=YES/NO 用於記錄慢查日誌的記錄可結合explain查看語句執行
過程,找出問題,優化查詢語句,或者優化表(表拆分,減少數據冗餘),
建立合適的索引提高查詢效率
thead_cache_size = # 緩存連接線程的個數,可以讓mysql不用經常爲每個連接創建線程
可查看connections和therads_created狀態變量確定,增大可提升***能
table_cache = # 表緩存大小,緩存打開過的表,可結合open_tables,opened_tables的值是否調大
如果能在緩存中去肯定快點
tmp_table_size = # 臨時表大小,如果超過臨時表會寫入磁盤。磁盤的***能都知道慢
qcache_lownmem_prunes 是一個狀態變量,如果過大表示query_cache_size可能過小,
緩存經常置換
query_free_blocks 狀態變量,如果過大表示緩存碎片過多,可用flush query cache進行碎片整理
3,OS
使用內存大葉提高tlb的命中率
內存分頁,每個頁4096字節
每個進程看到自己的內存都很大在32位上爲4G 64位就是16E,是虛擬的
多個虛擬內存可以指向同一個物理內存,比如說使用epoll的nginx提升***能又環保
在內存中每個進程有一個page table 存放物理內存到虛擬內存的對應關係
由虛擬內存到物理內存的轉換稱爲page walk,轉換的結果會緩存在cpu的tlb中
下次在要轉換的時候先查tlb如果hit直接還回用 x86info -c查看tlb
context switch上下文切換
每次上下文切換的時候tlb會被清空
tlb: Translation look-aside buffer
有了tlb***能大概提升15% tlb是用一種叫CAM的東西做的
CAM:content addressable memory
如果一個程序用的內存很大超過8G,如果還使用4K大小的內存頁,會有很大的***能損失,
因爲要從虛擬內存轉換到物理內存嘛,頁表大了查詢很慢,而且放頁表很佔空間
所以使用內存大葉:huge pages 一般爲4M 2M
太大也會浪費內存
要使用內存大葉必須先分配好,可以寫在grub的kernel參數上,也可以調,
不過後來調可能沒有那麼多的內存大葉,因爲大葉必須要是連續的,
如果內存使用過了很可能因爲太多的內存碎片,造成內存的不連續,分不出那麼多的大葉出來
用使用大葉必須程序支持,而且不能交換到磁盤
進入正題
[root@node2 ~]# sysctl -w vm.nr_hugepages=10
vm.nr_hugepages = 10
[root@node2 ~]# cat /proc/meminfo
HugePages_Total: 10
HugePages_Free: 10
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
配置使用大頁內存的用戶組mysql
[root@localhost ~]# sysctl -w vm.hugetlb_shm_group=306
vm.hugetlb_shm_group = 306
vim /etc/security/limits.conf
@mysql soft memlock unlimited
@mysql hard memlock unlimited
修改/vim /etc/sysctl.conf 默認就很大可以不用改
# Increase the amount of shmem allowed per segment
# This depends upon your memory, remember your
kernel.shmmax = 68719476736
# Increase total amount of shared memory.
kernel.shmall = 4294967296
large-pages 寫在mysql配置文件
mysql> show global variables like 'large%';
+---------------------+---------+
| Variable_name | Value |
+---------------------+---------+
| large_files_support | ON |
| large_page_size | 2097152 |
| large_pages | ON |
使用什麼文件系統,ext3就不用在用了,ext4 XFS (rw,noatime,nodiratime,barrier=0)
現在的很多文件系統會在數據提交時強制底層設備刷新cache,避免數據丟失,
稱之爲write barriers。但是,其實我們數據
庫服務器底層存儲設備要麼採用RAID卡,RAID卡本身的電池可以掉電保護;
要麼採用Flash卡,它也有自我保護機制,保證數據不會丟失。
所以我們可以安全的使用nobarrier掛載文件系統。設置方法如下:
對於ext3, ext4和 reiserfs文件系統可以在mount時指定barrier=0;
對於xfs可以指定nobarrier選項
noatime你懂的
IO調度:[deadline] 數據庫的磁盤調度算法
echo deadline >/sys/block/sda/queue/scheduler
我們也可以直接在/etc/grub.conf的kernel行最後添加elevator=deadline來永久生效
page資源傾斜給數據庫, 儘量不浪費,兼顧臨時內存申請
避免NUMA架構帶來的zone內存分配不均而導致的swap現象
cache大部分由InnoDB日誌產生,適時清除,限制page數量
#############################
# numactl --interleave=all mysqld 關掉了NUMA特***也可加內核參數numa=off
# sysctl vm.drop_caches = 1 回收內存的
vm.swappiness=0 vm.swappiness設置爲0表示儘量少swap,
100表示儘量將inactive的內存頁交換出去
inactive 內存顧名思義,就是那些被應用程序映射着,但是“長時間”不用的內存
#cat /proc/meminfo | grep -i inact
#echo "vm.swappiness = 0" >>/etc/sysctl.conf
你仔細檢查的話,有些服務器上會有的一個有趣的現象:你cat /proc/cpuinfo時,
會發現CPU的頻率竟然跟它標稱的頻率不一樣:
爲了環保嘛,但是mysql一定要全速的,在bios改
4,SQL語句
MySQL數據庫開發-石展
1,儘量不在數據庫做運算
>別用腿想事,那是腦瓜子的職責
複雜運算移到程序端的cpu
儘可能簡單的運用mysql
2,控制表單數據量
純int不超過1000W
含char不超500W
合理分表,建議單庫不超過300-400個表
3,保持表身段苗條
單表字段不超過20-50
4,平衡範式和冗餘
適當犧牲範式,加入冗餘,效率優先,提升***能
5,拒絕3B
big sql big transaction big batch(大批量)
6,用好數字字段類型
數字型vs字符型索引
更高效,查詢更快,佔用空間更小 如用無符號的int存儲ip,而非char
7,優先使用enum或set
enum佔用1字節,轉爲數值運算
set視節點定,最多佔用8字節
8,避免使用null字段
很難進行查詢優化
null列加索引需要額外空間
含null複合索引無效
舉例:‘a’ char(32) default null 錯
‘b’ int(10) not null 錯
'c' int(10) not null default 0 對
9,少用並拆分text/blob
強制生成硬盤臨時表
浪費更多空間
若要使用則拆分到單獨的表
10,不在數據庫裏存圖片
11,謹慎合理添加索引
改善查詢
減慢更新
索引不是越多越好
能不加索引儘量不加
結合核心SQL優先考慮覆蓋索引
舉例:不要給***別加索引
12,字符字段必須建前綴索引
舉例:'pinyin' varchar(100) default null comment '小區拼音',
key 'idx_pinyin' ('pinyin'(8))'
)engine=innoDB
13,不在索引列做運算
無法使用索引
導致全表掃描
14,自增列或全局ID做INNODB主鍵
對主鍵建立聚簇索引
聚簇索引:索引和數據在一塊,無指針,只能有一個,因爲索引排序。輔助索引指向了聚簇索引並不指向數據
二級索引存儲主鍵值
主鍵不應更新修改
按自增順序插入值
忌用字符串做主鍵
聚簇索引分裂
推薦用獨立於業務的AUTO_INCREMENT列或全局ID生成器所代理主鍵
若不指定主鍵,InnoDB會用唯一的非空值索引代替
15,儘量不用外鍵
外鍵可節省開發量
有額外的開銷
逐行操作
可到達其他表,意味着鎖
高併發時容易死鎖
由程序保證約束
16,SQL語句儘可能簡單
傳統設計思想,BUT MySQL NOT
一條SQL只能在一個CPU運算
5000+QPS的高併發中,1秒大SQL意味着?
可能一條大SQL就把整個數據庫堵死
拒絕大SQL,拆分多條簡單SQL
簡單SQL緩存命中率更高
減少所表時間,特別是MyISAM
用上多CPU
17,保持事務短小
事務/連接使用原則:即開即關,用完即關
與事務無關的操作放到事務外面,減少鎖資源的佔用
不破壞一致***的前提下,使用多個短小的事務代替長事務
18,儘可能避免使用SP/TRIG/PUNC
儘可能少用存儲過程
經可能少用觸發器
減少使用MYSQL函數對結果進行處理
用客戶端程序負責
19,儘量不用SELECT *
更多消耗CPU,內存,IO,網絡帶寬
先向數據庫請求所有列,然後丟掉不需要的列?
20,改寫OR爲IN()
OR效率:O(n)
IN效率:O(Log n)
當n很大時,OR會慢很多,注意控制IN的個數建議小於200
舉例:select * from opp where phone = '123456' or phone = '42242233'
-->
select * from opp where phone in ('123456','42242233')
21,改寫OR爲UNION
22,避免負向查詢和%前綴模糊查詢
B+Tree
使用不了索引
導致全表掃描
舉例:mysql> select * from post where title like '北京%';
293 rows in set (0.01 sec)
mysql> select * from post where title like '%北京%';
572 rows in set (3.27 sec)
23,減少count(*)
count(*)開銷大
24,limit高效分頁
25,用UNION ALL 而非UNION
UNION有去重開銷
26,分解聯結保證高併發
高併發的DB不建議進行兩個表以上的JOIN
27,GROUP BY去除排序
GROUP BY實現
分組,自動排序
28,同數據類型的列值比較
原則:數字對數字,字符對字符
數值列於字符類型比較
同時轉換爲雙精度
進行比對
字符列與數值類型比較
字符列整列轉爲數值
不會使用索引
29,Load data
Load data 比insert快20倍
儘量不用INSERT ...SELECT
延遲,同步出錯
30,Konw Every SQL
EXPLAIN
show profile
mysqllsla
show slow log
show query_response_time(percona)
show processlist
msyqldumpslow
show profile
31,隔離線上線下
32,禁止未經DBA確認的子查詢
例子:mysql> insert into table1 (select * from table2);可能會導致複製異常
5,索引的構建
mysql優化的重點,使用什麼索引在哪使用索引太關鍵了
一條好的索引可以讓***能提升n倍,看情況,索引的不好***能是會下降的
因爲更新字段還得更新索引,不要數據1G,索引9G。這樣就不好了
explain
EXPLAIN列的解釋:
mysql> explain select user,host,password from user;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | user | ALL | NULL | NULL | NULL | NULL | 5 | |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
下面的在網上貼的
table:顯示這一行的數據是關於哪張表的
type:這是重要的列,顯示連接使用了何種類型。從最好到最差的連接類型爲const、eq_reg、ref、range、indexhe和ALL
possible_keys:顯示可能應用在這張表中的索引。如果爲空,沒有可能的索引。可以爲相關的域從WHERE語句中選擇一個合適的語句
key: 實際使用的索引。如果爲NULL,則沒有使用索引。很少的情況下,MYSQL會選擇優化不足的索引。這種情況下,可以在SELECT語句中使用USE INDEX(indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制MYSQL忽略索引
key_len:使用的索引的長度。在不損失精確***的情況下,長度越短越好
ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數
rows:MYSQL認爲必須檢查的用來返回請求數據的行數
Extra:關於MYSQL如何解析查詢的額外信息。將在表4.3中討論,但這裏可以看到的壞的例子是Using temporary和Using filesort,意思MYSQL根本不能使用索引,結果是檢索會很慢
extra列返回的描述的意義
Distinct:一旦MYSQL找到了與行相聯合匹配的行,就不再搜索了
Not exists: MYSQL優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標準的行,就不再搜索了
Range checked for each Record(index map:#):沒有找到理想的索引,因此對於從前面表中來的每一個行組合,MYSQL檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連接之一
Using filesort: 看到這個的時候,查詢就需要優化了。MYSQL需要進行額外的步驟來發現如何對返回的行排序。它根據連接類型以及存儲排序鍵值和匹配條件的全部行的行指針來排序全部行
Using index: 列數據是從僅僅使用了索引中的信息而沒有讀取實際的行動的表返回的,這發生在對錶的全部的請求列都是同一個索引的部分的時候
Using temporary 看到這個的時候,查詢需要優化了。這裏,MYSQL需要創建一個臨時表來存儲結果,這通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上
Where used 使用了WHERE從句來限制哪些行將與下一張表匹配或者是返回給用戶。如果不想返回表中的全部行,並且連接類型ALL或index,這就會發生,或者是查詢有問題不同連接類型的解釋(按照效率高低的順序排序)
system 表只有一行:system表。這是const連接類型的特殊情況
const:表中的一個記錄的最大值能夠匹配這個查詢(索引可以是主鍵或惟一索引)。因爲只有一行,這個值實際就是常數,因爲MYSQL先讀這個值然後把它當做常數來對待
eq_ref:在連接中,MYSQL在查詢時,從前面的表中,對每一個記錄的聯合都從表中讀取一個記錄,它在查詢使用了索引爲主鍵或惟一鍵的全部時使用
ref:這個連接類型只***誆檠褂昧瞬皇俏┮換蛑骷募蛘呤欽廡├嘈偷牟糠鄭ū熱紓米鈄蟊咔白海┦狽⑸6雜諡暗謀淼拿懇桓魴辛希考鍬級冀穎碇卸臉觥U飧隼嘈脫現匾覽滌詬菟饕ヅ淶募鍬級嗌佟繳僭膠
range:這個連接類型使用索引返回一個範圍中的行,比如使用>或<查找東西時發生的情況
index: 這個連接類型對前面的表中的每一個記錄聯合進行完全掃描(比ALL更好,因爲索引一般小於表數據)
ALL:這個連接類型對於前面的每一個記錄聯合進行完全掃描,這一般比較糟糕,應該儘量避免
1, TPS: 每秒事務量,通過以下方式來得到客戶端應用程序所請求的 TPS 值,
TPS = (Com_commit + Com_rollback) / Seconds
通過如下命令可以獲得相應的值
Com_commit = /bin/mysqladmin extended-status --relative --sleep=1|grep -w Com_commit
Com_rollback = /bin/mysqladmin extended-status --relative --sleep=1|grep -w Com_rollback
TPS = $Com_commit + $Com_rollback
2, QPS: 每秒Query 量,這裏的QPS 是指MySQL Server 每秒執行的Query總量,通過Questions 狀態值每秒內的變化量來近似表示,所有,insert delete update都算
QPS = /bin/mysqladmin extended-status --relative --sleep=1|grep -w Questions
PS: 仿照上面的方法還可以得到,mysql server 的每秒 查詢,更新量等等,如:
每秒SLECECT量 = /bin/mysqladmin extended-status --relative --sleep=1|grep -w Com_select