目錄
一:基礎篇
二:索引原理和SQL優化
三:事務原理
四:緩存策略
一:基礎篇
1:定義:按照數據結構來組織、存儲和管理數據的倉庫;是一個長期存儲在計算機內的、有組織的、可共享 的、統一管理的大量數據的集合;
2:MySql中含有內部連接池用來管理緩沖用戶的連接,以及線程處理需要緩存的需要。并且使用IO多路復用的select + 阻塞IO。并且他的命令處理是在多線程中并發處理的。
3:數據庫三范式:先保持原子性不可分割 / 確保表中的每列和主鍵完全依賴 / 確保每列和主鍵直接相關不是間接相關。但是有時候沒有必要使用三范式,會導致數據庫業務涉及到的表變多,造成更多的連表查詢,導致整個性能降低。因此需要考慮反范式。
4:五大約束:非空約束,自增約束,唯一約束,主鍵約束包括非空且唯一,外鍵約束。其中外鍵約束在 innodb 中支持,并且滿足事務。
5:刪除數據
drop(DDL):速度快,刪除整張表結構和表數據,包括索引,約束,觸發器等。但是刪除后不能回滾,會進行釋放空間。
truncate(DDL):速度比較快,會刪除表數據,其他字段會保留(自增字段置為1),但是也不能回滾,會釋放空間,以頁單位進行刪除。
delete(DML):速度慢,刪除部分字段或者全部字段,其他保留,他是一個條件刪除,可以進行回滾,是標記刪除(實際并未刪除),可以進行逐行刪除。
6:去重是group by ,select distinct 。條件判斷是:where,group by ... having , ...join ... on ... 。三種
7:視圖:視圖是邏輯表,自身不含數據,內容是通過查詢得到。安全:使用視圖,用戶只能看到他們被允許查詢到的結果集,而對表的權限管理無法做到限制某些行和列,視圖卻可以。數據獨立,源表中的數據修改,對視圖沒有影響。視圖可以減少重復語句的書寫,并且還是個重構利器:如果需要將一個表進行拆分成兩個表,我們可以使用視圖來進行操作,創建出兩個視圖,這樣我們只需要更改數據庫結構,而不用修改應用程序。
8:觸發器:觸發器的執行是由事件自動觸發,而不是程序調用和手工啟動。比如當DML操作的時候,就會激活執行。
二:索引原理和SQL優化
MySql索引原理和SQL優化_mysql 全文索引sql-CSDN博客
1:索引是什么:索引是一種有序的存儲結構,它將單個或多個列的值進行排序。
2:索引分類:主鍵索引,唯一索引,非空索引,普通索引,組合索引,全文索引。在主鍵索引的B+數種中包含數據的全部信息。全文索引是將存儲在數據庫中的整本書整篇文章的任意內容信息查找。關鍵詞是:FULLTEXT。
3:為什么使用B+數索引,而不使用紅黑樹結構?
????????首先B+數相對于高瘦的紅黑樹來說,B+樹是胖矮的,在葉子節點中存放數據,并且葉子節點還串聯在一起,而非葉子節點中存放索引信息。無論是葉子節點還是非葉子節點都是存放在頁中的。這樣當我們查找數據的時候,我們會擁有更少的磁盤IO,而且更方便范圍查找,因為葉子節點是串聯在一起的,找到第一個葉子節點后,可以相繼找出其他節點。但是對于紅黑樹來說,需要不斷進行搜索。并且每個索引都對應一個B+樹。
為什么采用多路的樹結構?一個節點有多條鏈路,相較于平衡二叉搜索樹是一個更加矮胖的結構,樹的高度更低,可以較少的磁盤io次數來索引數據。
為什么非葉子節點只存儲索引信息?B+樹節點映射固定的大小磁盤數據,可以包含更多的索引信息。能快速鎖定數據所在葉子節點的位置。
為什么葉子節點依次相連?便于范圍查詢,避免中序遍歷回溯回去查找下一個節點。
4:什么時候使用索引呢?
? ? ? ? 首先我們的索引使用的位置是在where,group by ,order by 的后面使用索引。那么不適合使用索引:就是沒有這一些判斷條件以及區分度不高的列(數據很相似的),需要經常修改的列,表數據量少的。我們創建B+樹類型的索引就是為了通過比較來找到我們所需要的數據,但是當區分度不高的時候,反而會降低速度,如果經常修改這個列,那么我們的B+的結構就要經常變化,更加影響速率,表的數據較少的時候,沒有必要去創建索引,創建索引反而會浪費空間。
5:索引方式:
每一個索引都有一個B+樹結構。
聚集索引:我們主鍵構造出的B+樹,葉子節點中存放數據,數據也是索引的一部分。并且主鍵索引就是聚集索引,沒有主鍵那就是唯一索引作為聚集索引。
輔助索引(二級索引):我們在輔助索引B+樹中,葉子節點并不是存儲的數據,而是存儲的主鍵id。當通過輔助索引查找到主鍵id后,我們再根據主鍵去查找聚集索引。這里也叫回表查詢。
覆蓋索引:是索引包含了查詢所需的所有列,即索引本身能夠覆蓋查詢的字段需求,無需再通過回表操作來獲取數據。通過使用覆蓋索引,可以提高查詢性能,減少不必要的磁盤I/O和數據傳輸。也就是我們不要select * 而是select 。。。什么的。
最左匹配規則:對于組合索引來說,我們使用必須要滿足從左往右的規則:id,name,age。這三個只能使用:id,name,age;id,name;id;這三種方式來使用索引。
6:索引的失效和索引原則
索引失效:
1:當where? A and B 的時候,其中一個沒有索引,那么就會失效。
2:當索引字段參與了運算。
3:索引字段發生隱式轉換。
4:LIKE模糊匹配,通配符以“%”開頭。
5:在索引字段上使用NOT <> !=?
6:組合索引中,沒有滿足最左匹配。
索引原則:
1:查詢頻次較高且數據量大的表建立索引,索引選擇使用頻次較高,過濾效果好的列或者組合。
2:使用短索引,這樣節點包含的信息多,有較少的磁盤IO操作。
3:很長的動態字符串,考慮使用前綴索引。
4:組合索引中,考慮最左匹配原則,和覆蓋索引。
5:選擇區分度高的列,也就是值相同的越少越好。
6:擴展索引,在現有索引的基礎上,添加復合索引,最多6個索引。
7:不要select * ,盡量列出所需要的列,方便使用覆蓋索引。
8:索引列盡量設置為非空
9:可以開啟自適應hash索引。
三:事務原理
MySql 事務原理 - 面試_面試題 mysql事物實現原理-CSDN博客
1:事務
事務是什么:本質是一個并發的控制單元,用戶定義的一個操作序列,這些操作要么都做要么都不做,滿足原子操作。
什么時候使用事務:并發連接訪問的時候。
事務的目的:從一種一致性狀態轉變成另一種一致性狀態的時候,保證系統始終處于一個完整且正確的狀態。
2:ACID特性中的隔離性
臟讀,不可重復讀,幻讀。以及持久性中使用redolog寫入物理日志,寫入磁盤。
undolog:通過MVCC記錄事務DML操作提交后產生的行數據版本信息。記錄DML操作步驟,用于回滾業務,通過逆運算回滾。
redolog:事務提交后,記錄DML操作對應物理頁修改的內容。
3:隔離級別
read_uncommitted(讀未提交):讀(不做任何處理),寫(自動加X鎖)。臟讀、不可重復讀、幻讀。
read_committed(讀已提交)(RC):讀(通過MVCC,讀取最新版本的數據),寫(自動加X鎖)。不可重復讀、幻讀。
repeatable_read(可重復讀)(RR):讀(通過MVCC,讀取開啟事務前的行數據),寫(自動加X鎖)。幻讀。
serializable(可串行化):讀(自動加S鎖),寫(自動加X鎖)。
4:隔離級別的并發異常
臟讀:一個事務讀到另一個未提交事務修改的數據。
不可重復讀:一個事務內兩次讀取同一個數據不一樣。一個事務提交之后,另一個事務中也會發現這個被修改的變量。
幻讀:一個事務內兩次讀取同一個范圍內的記錄得到的結果集不一樣,當前讀和快照讀不一致。我們在一個事務中插入一個數據,我們另一個事務在查詢的時候并未看到這個數據,但是插入的時候發現報錯。
我們數據庫默認的隔離級別就是RR,也就是可以發生幻讀。我們可以不用提升隔離級別就能解決這個問題,那就是手動加鎖。具體加鎖操作看文章即可。
5:MVCC
MVCC是多版本并發控制,保證數據的一致性和并發性。可以使多個事務在同時訪問數據的時候,各自看到不同版本的數據,不會互相打擾,這樣就可以避免鎖和等待了。
read_view 是一個事務開始時創建的視圖,他決定了事務能夠看到的數據庫版本中的數據版本,其中包括自身的事務id,已啟動但未提交的事務id列表。
其中聚集索引記錄的隱藏列存儲在行中,這個行中包括該事務id。以及數據會指向之前的數據版本,用于回滾操作。
6:事務的可見性問題
事務可以看到自身事務的修改。事務之間的可見性是:已經提交的事務是可以看到的,后啟動的事務是不可見的,在事務列表中已啟動但未提交的不可見,已提交可見的。
7:RC和RR的區別
因為RC和RR都采用了MVCC,但是RC是讀已提交,每次讀取數據就會產生一個read_view。而RR是開啟事務的時候才會生成一個read_view,一直用到事務結束,也就是一直能看到一個數據版本。因此RC每次讀都能看到最新數據,所以產生了不可重復讀,而RR中解決了。
8:什么是快照讀和當前讀:快照讀就是從之前拍攝的一個快照中進行讀取數據,而當前讀就是直接讀取最新數據。快照讀并未采用鎖,當前讀加鎖了。
四:緩存策略
MySQL的緩存策略_mysql 數據庫的緩存策略-CSDN博客
1:MySQL?緩存方案用來干什么?
首先是MySql的緩存方案,他自己的緩存方案和業務層面是沒有關系的,雖然MySQl也是用來緩存熱點數據的,但是這些熱點數據并不是用戶自定義的,而是索引,記錄等。他的緩存是從它自身出發的。
2:redis緩存方案:redis是內存數據庫讀取速度十分快,因此我們采用redis作為我們的緩沖數據庫,用來緩存用戶定義的熱點數據,用戶直接從緩存中讀取熱點數據,降低數據庫的讀寫壓力。而MySql是主要作為數據的落盤。
3:提升MySql訪問性能的方式
1:讀寫分離:利用MySql的主從復制,我們設置多個從數據庫,一個主數據庫,我們進行主從復制的操作,然后主數據庫主要負責寫的操作,而其他從數據庫負責讀的操作。這樣讀寫分離之后,會降低主數據庫讀的壓力。但是當碰到對于讀的時效性很強的時候,我們不得不讀取主數據庫了。
2:連接池:我們MySql中存在連接池的組件,會開啟多個線程去服務這幾個連接。有了連接池可以大大提高并發訪問數據庫的能力。并且網絡模型為select + 阻塞IO模型。我們當開啟事務的時候,我們要保證這事務中的sql語句全部在一個線程中執行。
3:異步連接:可以采用非阻塞IO的方式,也就是異步方法。
4:熱點數據的讀寫策略(redis)
1:安全為主
?如果要以安全為主,我們就要避免主數據庫和從數據庫讀取的數據不同的問題。當我們先寫入MySQL后,必然會出現MySQL與Redis數據不同的問題,那么我們就不能先寫入MySQL。而是要先刪除Redis中的數據,然后再寫入MySQL,最后將MySQL中的數據同步到Redis中去,這樣就保證兩方的數據一致了。但是我們的緩存方案就是為了提升效率,現在卻為了安全而降低了效率,這是我們不愿看到的。
2:速度為主
如果要以效率為主,我們可以先寫入緩存,并且設置過期時間(大約是200毫秒),然后再寫入MySQL,當寫入MySQL后,我們再將MySQL中的數據同步到Redis中去。當同步到Redis中去的時候,這個過期時間也就到期了。過期時間是與MySQL網絡傳輸時間+MySQL處理時間+MySQL同步到Redis的時間。有個問題是如果當寫入MySQL寫入失敗,這個時候Redis中含有數據,那么他就會提供臟數據。但是這個問題也就200毫秒的存活時間,因為從數據庫會找主數據庫進行同步。
5:緩存問題的解決方法
1:緩存穿透
問題:如果黑客讓客戶端一直讀取MySQL和Redis中都不存在的數據,那么所有的讀取操作都落在了MySQL中,那么就會造成MySQL中訪問的性能急劇降低。
解決:如果在Redis和MySQL中讀取的數據都不存在,那么就在Redis中設置一個<Key,nil>,代表查找的這個熱點數據不存在。或者部署布隆過濾器(類似于哈希表),使這些數據只能增加,不能刪除,具體可以搜一搜。
2:緩存擊穿
問題:如果Redis中沒有,但是MySQL中有,也就是說本來一個熱點數據,在Redis中存在,但是過期了,那么大量的并發請求讀取操作就會落到MySQL中,這樣就造成MySQL訪問的性能急劇降低。
解決:我們可以將過熱的數據設置成不過期的狀態。或者是添加分布式鎖,將并發的請求操作,變成串行執行。
3:緩存雪崩
問題:我們在寫入Redis中的數據是需要加入過期時間的,但是當我們不小心將多個過熱數據的過期時間設置成統一時間,就會面臨大量熱點數據集中失效的問題,雖然失效,但是在MySQL中還是存在這個數據,所以大量的請求讀取操作就會落到MySQL中去,就會造成MySQL訪問性能急劇降低。
解決:我們可以將這個過期時間給錯開,避免同時過期。當然我們可以在重啟MySQL的時候,先將一些熱數據先緩存到Redis中。
五:一些小問題
1:MySQL的集群是用什么樣的方式去增加并發量
使用連接池技術,合理使用索引,優化SQL語句,分庫分表,使用存儲過程。
2:B樹和B+樹的區別
1.B樹只適合隨機檢索,B+樹支持隨機檢索和順序檢索
2.B+樹空間利用率高,可以減少IO次數,磁盤讀寫代價更低。 一般來說索引本身也很大,往往以索引文件的形式存儲在磁盤上,這樣索引查找過程就要產生磁盤IO消耗。B+樹的內部節點只作為索引使用,其內部節點(非葉子節點)比B樹更小,判斷能容納的節點中關鍵字更多,一次讀取到的鍵更多。 3.B+樹查詢效率更穩定,因為數據存放在葉子節點。
4.B樹在一定程度上也提高了磁盤IO性能,但沒有解決遍歷效率低下的問題。B+樹的葉子節點都使用指針順序連接在一起,只要遍歷葉子節點就可以實現所有值。
5.增刪文件時,B樹需要重新調整樹結構。B+樹不需要調整樹結構,因此B+樹效率更高。
3:數據庫的ACID怎么實現
1:原子性:要么都發生要么都不發生,所以需要實現回滾的操作,那么我們就要實現undolog的回滾日志。我們在數據庫執行操作的時候,我們生成一個undolog,里面包含的是數據庫的SQL,當執行失敗的時候,我們通過我們的undolog進行回滾,也就是當插入insert的話,那我們就執行delete,如果是update,那我們就反向執行update。反正就是通過undolog進行回滾操作。
2:一致性:是數據庫的完整性和一致性,我們使用其他三個特性來完成這一個特性。
3:隔離性:對于隔離性需要實現MVCC
4:持久性:對于持久性就是我們實現redolog,我們采用預先寫的方法,也就是我們在修改之前先將操作寫入日志,然后再寫入bufferpool,這樣mysql宕機之后的話,我們重啟就可以讀取到redolog的數據。
4:mysql的binlog是什么
binlog是二進制日志,他記錄了數據庫上的所有改變,并以二進制的形式保存在從磁盤中。它可以用來查看數據庫的變更歷史,數據庫增量備份和恢復,mysql的主從數據庫的復制。
5: 當前讀和快照讀
當前讀:像select lock in share mode ,select for update ,update ;insert; delete 。這些操作都是一種當前讀,為什么叫當前讀,就是他讀取的是當前記錄的最新版本,讀取時還要保證其他事務不能修改當前記錄,所以會對記錄進行加鎖。
快照讀:像不加鎖的select就是快照讀。快照讀的實現是基于MVCC的操作實現的,他的操作避免了加鎖的操作,只是拿取一個數據版本。
6:數據庫鎖
在MySQL中,鎖可以分為共享鎖和排它鎖兩種類型。共享鎖用于讀取數據,而排它鎖用于修改數據。當一個事務獲得了排它鎖后,其他事務就不能再對該數據進行修改,直到該事務釋放鎖為止。
7:項目怎么進行死鎖檢測
可以使用jstack工具
或者寫死鎖檢測的代碼:Linux下的死鎖檢測組件(分模塊講解)_linux死鎖檢測-CSDN博客
8:什么時候使用讀已提交
????????讀已提交是一種常見的隔離級別,它可以提高并發性和數據準確性:訂單系統
????????假設有一個在線商店,它需要處理大量訂單。多個用戶可能同時提交訂單,如果不使用讀已提交隔離級別,有可能會出現數據混亂或錯誤的情況。例如,一個用戶提交訂單時,第二個用戶同時查看訂單,但卻看到了已提交但未完成的訂單,導致訂單重復或缺失。使用讀已提交隔離級別可以避免這種情況,確保每個用戶都只看到已經提交并生效的訂單。
9:搜索慢怎么解決
????????我們通過使用 EXPLAIN 來查看 SQL 語句的具體執行過程。 原理:模擬優化器執行 SQL 查詢語句,從而知道 MySQL 是如何處理 SQL 語句的。
? ? ? ? 首先我們需要找到SQL這個語句在哪里,通過 show processlist 列出較慢的連接通道來 以及使用慢查詢日志來找到具體的SQL語句。再分析SQL中我們要先查看在where、group by、order by中是否使用索引,如果沒有使用,那么就可以考慮是否添加索引,然后繼續優化SQL語句中in和not in 變成聯合查詢,并且減少整體的聯合查詢。以及一個隱形的問題:age問題,應該存儲出生年月,讓客戶端進行計算年紀。
https://github.com/0voice