MYSQL實戰-------丁奇(極客時間)學習筆記


1.基礎架構:一條sql查詢語句是如何執行的?

mysql> select * from T where ID=10;

 2.基礎架構:一條sql更新語句是如何執行的?

mysql> update T set c=c+1 where ID=2;

 

redo log

(1)存儲引擎的日志,InnoDB特有的;

(2)物理日志

(3)循環寫,空間固定會用完;

binlog

(1)server端日志,所有引擎都有;

(2)邏輯日志

(3)追加寫,文件寫到一定大小,切換下一個,並不會覆蓋之前的日志;

redolog的寫入拆分成兩個步驟:prepare和commit

redo log 和binlog都可以用於表示事務的提交狀態,兩階段提交是為了維持這兩個狀態一致。

恢復:

注:正常執行redolog commit;崩潰恢復的時候可以接受redolog prepare並且binglog完整

 3.事務隔離

MyISAM不支持事務,InnoDB 支持事務

讀未提交:別人改數據的事務尚未提交,我在我的事務中也能讀到。
讀已提交:別人改數據的事務已經提交,我在我的事務中才能讀到。
可重復讀:別人改數據的事務已經提交,我在我的事務中也不去讀。(對賬的例子)
串行:我的事務尚未提交,別人就別想改數據。

https://blog.csdn.net/changhenshui1990/article/details/77161401

 4.索引(上)

 索引---目錄:提供數據查詢的效率

(1)哈希表:適合等值查詢的場景

缺點:范圍查找比較麻煩

哈希沖突:鏈表(兩個key生成的N一樣)

(2)有序數組:等值查找,范圍查詢性能都很好、只適合靜態存儲引擎

缺點:更新比較麻煩

(3)二叉搜索樹:每個節點的左兒子小於父節點,父節點又小於右兒子

InnoDB的索引模型

 B+樹索引模型

mysql> create table T(

id int primary key,
k int not null,
name varchar(16),
index (k))engine=InnoDB;

索引類型:主建索引、非主建索引

主建索引的葉子節點存儲:整行數據(聚簇索引),主建索引只要搜索id這個B+ Tree就可以拿到數據    

非主建索引葉子節點:主建的值(二級索引),普通索引先搜索索引拿到主建值,再到主建索引搜索一次(回表)

索引維護:

一個數據頁滿了,按照B+Tree算法,新增加一個數據頁,叫做頁分裂,會導致性能下降。空間利用率降低大概50%。當相鄰的兩個數據頁利用率很低的時候會做數據頁合並,合並的過程是分裂過程的逆過程。 

 

性能和存儲上來考慮,自增主建往往是更合理的選擇;遞增插入,追加,不會觸發葉子節點分裂。

業務字段用作主建:(1)只有一個索引(2)該索引必須唯一索引。-------------------------直接將這個索引設置成主建,避免每次查詢搜索兩棵樹。 

 5.索引(下)

(1)覆蓋索引:select ID from T where k betwe 3 and 5  不需要回表(回到主鍵索引樹搜索的過程,成為回表)

(2)前綴索引

(3)索引下推

總結:
1、覆蓋索引:如果查詢條件使用的是普通索引(或是聯合索引的最左原則字段),查詢結果是聯合索引的字段或是主鍵,不用回表操作,直接返回結果,減少IO磁盤讀寫讀取正行數據
2、最左前綴:聯合索引的最左 N 個字段,也可以是字符串索引的最左 M 個字符
3、聯合索引:根據創建聯合索引的順序,以最左原則進行where檢索,比如(age,name)以age=1 或 age= 1 and name=‘張三’可以使用索引,單以name=‘張三’ 不會使用索引,考慮到存儲空間的問題,還請根據業務需求,將查找頻繁的數據進行靠左創建索引。
4、索引下推:like 'hello%’and age >10 檢索,MySQL5.6版本之前,會對匹配的數據進行回表查詢。5.6版本后,會先過濾掉age<10的數據,再進行回表查詢,減少回表率,提升檢索速度

6.數據庫鎖——行鎖,表鎖

鎖:並發

(1)全局鎖:對整個數據庫實例加鎖,全庫數據備份的時候用;(InnoDB采用事務,可重復讀可以支持;不支持事務的引擎不能夠實現,采用FTWRL)  FTWRL——保證只讀

(2)表級鎖:表鎖、元數據鎖;

(3)行級鎖:InnoDB(行鎖)、MyIsAM(不支持行鎖)

7.索引選擇——唯一索引,普通索引

8.給字符串字段加索引

前綴索引

mysql> alter table SUser add index index1(email);

mysql> alter table SUser add index index2(email(6));

使用前綴索引,定義好長度,就可以做到既節省空間,又不用額外增加太多的查詢成本

 前綴索引對覆蓋索引的影響:

 其他方式: 倒序存儲、hash字段

9.mysql "抖"了一下

WAL:先寫日志,再寫磁盤

刷臟頁(flush)

(1)InnoDB的redo log滿了的時候

(2)內存不夠用了,先將臟頁寫到磁盤

(3)mysql系統空閑的時候

(4)mysql正常關閉的時候

10.數據刪除,表文件大小不變

InnoDB:表結構(.frm)定義和數據(.ibd)。

delete 命令其實只是把記錄的位置,或者數據頁標記為“可復用”,但磁盤文件的大小是不會變的。----空洞

重建表可以收縮空間

11.count(*)的實現

MyISAM:一個表的總行數存在了磁盤上

InnoDB:把數據一行一行地從引擎里面讀出來,然后累加

count(字段)<count(主建id)<count(1)約等於count(*)

12.order by的原理

(1)全字段排序:

 

缺點:
1.造成sort_buffer中存放不下很多數據,因為除了排序字段還存放其他字段,對sort_buffer的利用效率不高
2.當所需排序數據量很大時,會有很多的臨時文件,排序性能也會很差
優點:MySQL認為內存足夠大時會優先選擇全字段排序,因為這種方式比rowid 排序避免了一次回表操作

(2)rowId排序

 

優點:更好的利用內存的sort_buffer進行排序操作,盡量減少對磁盤的訪問
缺點:回表的操作是隨機IO,會造成大量的隨機讀,不一定就比全字段排序減少對磁盤的訪問

13.mysql隨機消息

mysql> select word from words order by rand() limit 3;

14.邏輯相同的sql語句性能相差很大

(1)條件字段函數

mysql> select count(*) from tradelog where month(t_modified)=7;

如果對字段做了函數計算,就用不上索引了,這是 MySQL 的規定。

對索引字段做函數操作,可能會破壞索引值的有序性,因此優化器就決定放棄走樹搜索功能。

mysql> select count(*) from tradelog where
-> (t_modified >= '2016-7-1' and t_modified<'2016-8-1') or
-> (t_modified >= '2017-7-1' and t_modified<'2017-8-1') or
-> (t_modified >= '2018-7-1' and t_modified<'2018-8-1');

(2)隱式類型轉換

mysql> select * from tradelog where tradeid=110717;

相當於 mysql> select * from tradelog where CAST(tradid AS signed int) = 110717;

對索引字段做函數操作,優化器會放棄走樹搜索功能。

(3)隱式字符串編碼轉換

15.查一行數據也很慢

(1)查詢長時間不返回:等MDL鎖、等flush、等行鎖

(2)查詢慢:沒有加索引,需要全表掃描;

16.幻讀

間隙鎖

17.mysql如何保證數據不丟失

18.mysql主備一致:binlog歸檔

binlog的格式:

(1)statement

(2)row

(3)mixed

19.mysql如何保證高可用

主備(寫數據)、主從(讀數據)------一主多從

20.mysql讀寫分離

21.join

select * from t1 straight_join t2 on (t1.b=t2.b) where t2.id<=50;
select * from t2 straight_join t1 on (t1.b=t2.b) where t2.id<=50;

第二條語句更好,小表作為驅動表;

22.分區表

CREATE TABLE `t` (
`ftime` datetime NOT NULL,
`c` int(11) DEFAULT NULL,
KEY (`ftime`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
PARTITION BY RANGE (YEAR(ftime))
(PARTITION p_2017 VALUES LESS THAN (2017) ENGINE = InnoDB,
PARTITION p_2018 VALUES LESS THAN (2018) ENGINE = InnoDB,
PARTITION p_2019 VALUES LESS THAN (2019) ENGINE = InnoDB,
PARTITION p_others VALUES LESS THAN MAXVALUE ENGINE = InnoDB);
insert into t values('2017-4-1',1),('2018-4-1',1);

 

索引參考:https://blog.csdn.net/tongdanping/article/details/79878302

https://www.cnblogs.com/yuyue2014/p/3662005.html

http://blog.codinglabs.org/articles/theory-of-mysql-index.html

https://www.cnblogs.com/liqiangchn/p/9066686.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM