mysql server組成
數據庫連接池:採用連接池,減少頻繁的開關連接
連接器-->分析器-->優化器-->執行器
連接器:控制用戶的連接
分析器:詞法分析,語法分析
優化器:優化sql語句,規定執行流程
執行器:sql語句的實際執行組件
存儲引擎:存放具體數據文件
選擇的存儲引擎不同,數據存放的位置不同,不同的文件格式。默認:innodb
innodb、mylsam:磁盤
memory:內存
查詢多使用 mylsam,增刪改多使用 innodb。
索引
存儲引擎的數據文件和索引存放位置不同,所以分爲聚簇索引和非聚簇索引
聚簇索引:數據和索引放在一起(innodb)
非聚簇索引:數據、索引都有單獨的文件(mylsam)
.frm存放的是表結構、ibd存放的是數據和索引
默認所有的數據文件放到表空間中,不會有單獨的ibd文件,需要自行設置
索引文件的結構(實現原理):
hash:散列表,對值取hash值,取模。hash衝突解決:讓高位參與運算(擾動函數)
二叉樹:左子樹必須小於根節點,右子樹大於根節點。二分查找。缺點:深度無法控制,插入時性能低。
BTree: 非葉子節點二元組[key,data],即非葉子節點也會存儲數據。
B+Tree:只有葉子節點才存儲數據,葉子節點帶順序索引。
拓展:AVL樹,自旋樹。二叉樹的缺點:很容易發展成一個鏈表,右邊的節點一直增長。所以纔會有AVL樹
索引的優缺點
優勢:可以快速檢索,減少I/O次數,加快檢索速度;根據索引分組和排序,可以加快分組和排序;
劣勢:索引本身也是表,因此會佔用存儲空間,一般來說,索引表佔用的空間的數據表的1.5倍;索引表的維護和創建需要時間成本,這個成本隨着數據量增大而增大;構建索引會降低數據表的修改操作(刪除,添加,修改)的效率,因爲在修改數據表的同時還需要修改索引表;
常用索引
主鍵索引、唯一索引、普通索引、組合索引、全文索引
普通索引:用表中的普通列構建的索引,沒有任何限制(覆蓋索引 見下方講解)
全文索引(FULLTEXT):用大文本對象的列構建的索引(下一部分會講解)
組合索引:用多個列組合構建的索引,這多個列中的值不允許有空值(最左匹配匹配)
覆蓋索引:表A,主鍵a,字段b(增加索引),字段c 。 語句select id from A where b = N , 使用了覆蓋索引,b字段的索引中存放了主鍵a的值,可以直接返回。但如果是*的話,就需要進行回表了。
或者表A,字段d,字段h ,語句 select d from A ,沒用覆蓋索引。對 d 增加索引,即實現了覆蓋索引
官網解釋覆蓋索引:只需要在一棵索引樹上就能獲取SQL所需的所有列數據,無需回表,速度更快
最左匹配:表A ,字段c,字段d,字段h。組合索引 d,h 。語句 select * from A where h=N,不會使用。
select * from A where d = N, 使用組合索引。即d,h索引 最左邊的 d 必須先匹配到
索引下推:索引下推一般可用於所求查詢字段(select列)不是/不全是聯合索引的字段,查詢條件爲多條件查詢且查詢條件子句(where/order by)字段全是聯合索引
例如表A ,字段a,字段b,字段c,聯合索引 b,c。
select * from A where b = N and c > 20 一般會使用聯合索引,將 符合條件 b = N 的數據查出來,然後回表查詢數據,再進行 c > 20的數據篩選。但是索引下推之後就: 符合條件的 b=N,聯合索引,所以 再從c 中找出 > 20 的,不符合條件的不要,再進行回表。
*在使用組合索引的時候可能因爲列名長度過長而導致索引的key太大,導致效率降低
解決:可以只取a和b的前幾個字符作爲索引
例如:ALTER TABLE 'table_name' ADD INDEX index_name(a(4),b(3));
InnoDB 是通過B+Tree結構對主鍵創建索引,如果沒有主鍵,會選擇唯一鍵,如果都沒有,會自動生成一個6位用戶不可見的id鍵。主鍵或唯一鍵創建索引,在節點的葉子節點存儲數據。
回表
當對非主鍵或唯一鍵創建索引時,例如對 name鍵創建索引,則該索引葉子節點存放的是主鍵或唯一鍵的值,需要回到上面再進行一次查找返回數據。
索引何時失效
(1)組合索引未使用最左前綴,例如組合索引(A,B),where B=b不會使用索引;
(2)like未使用最左前綴,where A like '%China';
(3)搜索一個索引而在另一個索引上做order by,where A=a order by B,只使用A上的索引,因爲查詢只使用一個索引 ;
(4)or會使索引失效。如果查詢字段相同,也可以使用索引。例如where A=a1 or A=a2(生效),where A=a or B=b(失效)
(5)如果列類型是字符串,要使用引號。例如where A='China',否則索引失效(會進行類型轉換);
(6)在索引列上的操作,函數(upper()等)、or、!=(<>)、not in等;
優化小細節:
- 不要對主鍵使用表達式 select * from table where id+1=5; 表達式不會使用索引
- 儘量使用主鍵查詢,而不是其它索引,主鍵查詢不會觸發回表
- 儘量使用前綴索引,例如一個字段很長,只使用前幾個字符作爲索引
- 查詢時,儘量使用最左匹配,例如where 和 order by 的字段。 order by 後面的字段不要一個 asc 一個 desc
- 能使用in 就不要使用 or ,能使用 union all 不使用 union ,union 會進行distinct : SELECT country FROM Websites UNION ALL SELECT country FROM apps ORDER BY country,
- 更新頻繁、字段區分度不高的不建議建立索引
- 創建索引的列,不允許爲null
- 當需要進行表連接的時候,最好不要超過3張表
- 如果明確知道只有一條數據返回,limit 1 能提高效率。limit 限制輸出
- 單表索引控制在5個內
- 創建索引的時候避免:過早優化,對系統不瞭解的情況下進行優化
遷移數據時先將索引關閉,遷移完成後再打開。
join 優化
- 儘量使用index 列
- 使用 left join 或者 right join ,而不是 join on,強制控制表的查詢順序。
- join 的時候,小表 loop 大表。例如 A表數據比較多, 則 b left join A, 或者 A right join B
索引監控
Handler_read_first 通過 index 獲取數據的次數
Handler_read_key 讀取索引第一個條目的次數
Handler_read_last 讀取索引最後一個條目的次數
Handler_read_prev 通過索引讀取下一條數據的次數
Handler_read_prev 通過索引讀取上一條數據的次數
Handler_read_rnd 從固定未知讀取數據的次數
Handler_read_rnd_next 從數據節點讀取嚇一跳數據的次數
CBO 基於成本的查詢優化
RBO 基於規則的查詢優化
查詢優化
- 查詢時使用: explain 查詢語句
- show profile;
- limit 第一個參數值不宜過大
- 多表查詢時不要使用*,而是指定具體需要返回的列名。儘量使用別名
- 查詢時排除不需要的列,而不是在應用中再獲取前多少條
- 將外連接轉換爲內連接,內連接比外連接效率高。內連接:關鍵字:inner join,外連接 left join、right join
- 能用一個表達式完成的不要用兩個。例如 a != 4 ,而不是 a > 4 or a <4
mysql 一頁大小 16K
binlog 和 redo log
爲什麼了有了binlog還要有redo log
redo log的兩階段
ACID
A :原子性 , C:一致性 , I : 隔離性 , D : 持久性。
原子性 undolog 實現,隔離性通過鎖機制實現,持久性 通過redolog實現,一致性其它三者。
mysql默認事務隔離級別:可重複讀
鎖機制
mylsam 默認表鎖
innodb 默認行鎖
innodb 的行鎖模式及加鎖方法
共享鎖(讀共享鎖)、排它鎖(寫獨佔鎖)
innodb 默認 對 update、delete、insert 自動給涉及的數據加上排它鎖。select語句默認不會加任何鎖類型。
innodb 只有通過索引條件檢索數據,才使用行鎖,否則,將使用表鎖。
排它鎖: select * from table where id = 1 for update;
mysql 主從複製和讀寫分離
mysql複製原理
1.master服務器將數據的改變記錄二進制binlog日誌,當master的數據發生改變時,將其改變寫入二進制日誌。
2.slave服務器會在一定時間間隔對master二進制日誌進行探測是否改變,發生改變,則開啓一個I/O Thread請求master二進制事件。
3.同時主節點爲每個I/O線程啓動一個dump線程,向其發送二進制事件。並保存至從節點本地的中繼日誌中,從節點將啓動mysql線程從中繼日誌讀取二進制日誌。在本地重放,使得其數據和主節點的保持一致。最後I/O Thread 和sqlThread 將進入睡眠狀態,等待下一次被喚醒。
就是說,主庫會生成兩個線程,一個I/O線程,一個sql線程。I/O線程會取請求主庫的binlog,並將得到的binlog寫道本地的relay-log(中繼)中。主庫會生成一個log dump線程,給從庫I/O線程傳binlog。sql 線程會讀取relay log文件的日誌,並解析成sql語句逐一執行。
注意:
1.master將操作語句記錄到binlog日誌中,然後授予slave遠程連接的權限(master一定要開啓binlog二進制日誌功能,通常爲了數據安全考慮,slave也開啓binlog功能)
2.slave開啓兩個線程:IO線程和sql線程。其中I/O線程負責讀取master的binlog內容到中繼日誌relay log中。sql線程負責從relay log日誌裏讀出binlog內容,並更新到slave數據庫裏。這樣就能保證slave數據和master數據一致。
3.mysql複製至少需要兩個mysql的服務,當然mysql服務可以在不同服務器上,也可以在同一臺上。
4.mysql複製最好確保master和 slave服務器 版本相同。如不能滿足,那麼保證master版本低於slave版本。
5.master和slave節點時間需同步。
具體步驟:
1.從庫通過手工執行change master to 語句連接主庫,提供了連接的用戶一切條件(user、password、ip、port),並且讓從庫知道,二進制日誌的起點位置(file名postion號);start slave
2.從庫的IO線程和主庫的dump線程建立連接
3.從庫根據change master to 語句提供的file名和position 號,IO線程向主庫發起binlog的請求
4.主庫dump線程根據從庫的請求,將本地binlog以events的方式發給從庫IO線程
5.從庫IO線程接收到binlog events,並存到本地relay-log 中,傳送過來的信息,會記錄到master.info中
6.從庫sql線程應用relay-log,並且把應用過的記錄到relay-log.info中,默認情況下,已經應用過的relay會自動被清理purge
mysql主從形式
1、一主一從
2、主主複製
3、一主多從
4、多主一從
5.聯級複製
步驟:
1. 創建數據庫 master、slave 執行 create database msb; use msb; msb:自己起名
2.在主(node1)服務器進行如下配置:
修改配置文件,執行以下命令打開mysql配置文件
vi /etc/my.cnf
在mysqld 模塊中添加如下配置信息
log-bin=master-bin #二進制文件名
binlog-format=Row #二進制日誌格式,有row、statement、mixed三種格式,row指的是把改變的內容複製過去,而不是把命令從服務器執行一遍。statement指的是在主服務器上執行的sql語句,在從服務器上執行同樣的語句,mysql默認採用基於語句的複製,效率比較高。mixed指的是默認採用基於語句的複製,一旦發現基於語句的無法精確的複製時,就會採用基於行的複製。
server-id=1 #要求各個服務器的id必須不一樣
binlog-do-db=msb #同步的數據庫名稱
3.配置從服務器登錄主服務器的賬號授權
--授權操作
set global validate_password_policy=0;
set global validate_password_length=1;
grant replication slave on *.* to 'root'@'%' identified by '123456';
--刷新權限
flush privileges;
4.從服務器的配置
#修改配置文件,執行以下命令打開mysql配置文件
vi /etc/my.cnf
#在mysqld模塊中添加如下配置信息
log-bin=master-bin #二進制的文件名
binlog-format=Row #二進制文件的格式
server-id=2 #服務器的id
5.重啓主服務器的mysqld服務
#重啓mysql服務
service mysqld restart
#登錄mysql數據庫
mysql -uroot -p
#查看master狀態
show master status;
6.重啓從服務器並進行相關配置
#重啓mysql服務
service mysqld restart
#登錄mysql數據庫
mysql -uroot -p
#連接主服務器
change master to
master_host='masterIp',master_user='root',master_password='1234556',master_port=3306,master_log_file='master-bin.001',master_log_pos=154;
#啓動slave
start slave
#查看slave 的狀態
show slave status\G (注意沒有分號)
7.此時可以在主服務器進行相關的數據添加刪除工作,在從服務器看相關的狀態
mysql主從同步延遲分析 (5.7版本之前存在)
mysql的主從複製都是單線程的操作,主庫對所有DDL和DML 產生的日誌寫進binlog,由於binlog是順序寫,所以效率很高。slave的sql Thread線程將主庫的DDL和DML操作事件在slave中重放。DML和DDL的IO操作是隨機的,不是順序,所以成本要高很多。另一方面,由於slq Thread也是單線程的,當主庫的併發比較高時,產生的DML數量超過slave的SQL Thread所能處理的速度,或者當slave中有大型query語句產生了鎖等待,那麼延時就產生了。
解決方案:
1.業務的持久化層的實現採用分庫架構,mysql服務可平行擴展,分散壓力。
2.單個庫讀寫分離,一主多從,主寫從讀,分散壓力。這樣從庫壓力主庫高,保護主庫。
3.服務的基礎架構在業務和mysql之間加入memecache或者redis的cache層。降低mysql的讀壓力。
4.不同業務的mysql物理上放在不同機器,分散壓力。
5.使用比主庫更好的硬件設備作爲slave,mysql壓力小,延遲自然小。
6.使用更加強勁的硬件設備。
MySQL 5.7新特性:並行複製原理(MTS)MySQL 5.7版本後,複製延遲問題永不存在
https://blog.csdn.net/A_man_only/article/details/84257702
Mysql 讀寫分離
生產不推薦 mysql-proxy ,性能不高
amoeba -- 阿里巴巴
具有負載均衡、高可用性、sql過濾、讀寫分離、可路由相關的query到目標數據庫、可併發請求多臺數據庫合併結果
主要解決:
1.降低數據切分帶來的複雜多數據庫結構
2.提供切分規則,並降低數據切分規則給應用帶來的影響
3.降低db與客戶端的連接數
4.讀寫分離