資料庫事務 資料庫索引 資料庫優化
資料庫三大正規化
-
第一正規化:原子性,每列都不可再分。舉例:省市&地址,地址不夠具體,無法按照省、市進行分類和查詢
-
第二正規化:唯一性,不存在部分依賴,每張表中都只能包含“一種”資訊,舉例:一張表中存在學生、課程和分數三個屬性,存在冗餘,可以分為學生表、課程表和成績表三個表
-
第三正規化:直接性,不存在傳遞依賴,每一列都應該和主鍵直接相關,不能包含其它表中的非主鍵列的資訊。舉例:一張表中存在學生、學校、學校地址三個屬性,學校地址和學校直接相關,不和學生直接相關,存在冗餘
儲存過程
-
儲存過程是指完成一個特定功能的sql語句集,經過編譯之後存放在資料庫中,使用者根據過程名稱和引數呼叫相應的過程。
-
儲存過程是可程式設計的函式,在資料庫中建立並儲存,由sql語句和控制語句組成。想在不同應用程式或平臺執行相同的函式或者封裝特定功能的時候是非常有用的,是面向物件的一種模擬實現。
-
優點
-
提高sql的靈活性和表達能力:程式過程是sql語句和控制語句的結合
-
標準的元件化程式設計:一次編譯,到處呼叫
-
提高執行效率:與批處理相比,只需要一次編譯和一次優化,執行效率更快
-
較少網路運輸量:只需要傳輸過程語句,不需要傳輸資料庫操作結果
-
安全保證:通過限制儲存過程的執行許可權來保證安全性
-
資料庫事務&ACID&隔離級別
-
資料庫事務:事務是併發控制的基本單位,由一系列的操作指令構成
-
事務的四大特性:ACID
-
原子性(Atomicity):事務中包含的所有操作要麼全部執行成功,要麼執行失敗回滾
-
一致性(Cinsistency):事務執行前和執行後都必須處於一致性的狀態
-
隔離性(Isolation):一個事務在執行過程中,不能被其它事務干擾,多個併發事務之間要相互隔離
-
永續性(Durability):已提交的事務的操作對資料庫中的資料的影響是永久的
-
-
不考慮隔離性可能帶來的問題
-
丟失更新:多個事務同時修改一條資料,後面事務的修改結果會覆蓋前面事務的修改
-
髒讀:一個事務處理過程中讀取了另外一個未提交事務中的資料
-
不可重複讀:一個事務處理過程中需要多次讀相同的內容,多次讀內容時讀取了另外一個已提交事務更新後的資料,導致前後讀取的資料不一致
-
幻讀:一個事務的操作需要多次讀取相同的資料,多次讀的過程中讀取到了另一個事務已提交的新插入後的資料,導致讀取的資料數量不同
-
-
隔離級別
-
Read Uncommited:讀取未提交的內容,可能導致髒讀、不可重複讀、幻讀。讀的時候不加鎖,寫的時候加行級寫鎖。
-
Read Committed:讀取提交的內容,可能導致不可重複讀、幻讀;大多數資料庫預設的隔離級別。讀的時候加行級讀鎖,讀完該行釋放,寫的時候加行級寫鎖,事務結束後釋放。
-
Repeated Read:可重讀,可能導致幻讀;MySQL預設的隔離級別;可以通過多版本併發控制解決幻讀的問題。讀的時候加行級讀鎖,事務結束後釋放,寫的時候加行級寫鎖,事務結束後釋放。
-
Serializable:序列化,最高的隔離級別,強制事務排序,在每個資料行上加上共享鎖,解決幻讀問題;可能導致大量的超時現象和鎖競爭。讀的時候加表級讀鎖,事務結束後釋放,寫的時候加表級寫鎖,事務結束後釋放。
-
鎖機制
-
按粒度劃分
-
行級鎖:開銷大、加鎖慢、會導致死鎖、加鎖粒度最小、鎖衝突概率最低、併發度最高
-
表級鎖:開銷小、加鎖快、不會導致死鎖、加鎖粒度最大、鎖衝突概率最高、併發度最低
-
頁級鎖:各項效能介於行級鎖和表級鎖之間,會發生死鎖
-
-
按級別劃分
-
讀鎖:阻塞寫鎖,不會阻塞讀鎖
-
寫鎖:同時阻塞讀鎖和寫鎖
-
-
InnoDB儲存引擎使用行鎖和表鎖,行級鎖機制依賴與索引,預設使用行級鎖
MyISAM儲存引擎使用表級鎖
索引
-
索引是建立在資料表列上的資料結構,可以用來儲存特定列的值並排序
-
優點是加快檢索速率,並且可以保證資料的唯一性,加速表的連線等等;缺點是索引的建立和維護需要時間開銷,同時也會佔用實體記憶體,因此需要進行範圍查詢、需要排序、需要頻繁查詢以及主鍵的列建立索引提高查詢和檢索的效率
-
常見的索引的資料結構:B+樹、hash索引
-
InnoDB查詢引擎的索引和MyISAM查詢引擎的索引
-
InnoDB的主索引中資料檔案本身是索引檔案,可以提供非常快速的主鍵查詢效能;輔助索引中資料檔案是主鍵,需要再根據主索引表進行內容查詢,所以主鍵不要設定太大而且最好自增,方便B+樹的順序查詢
-
MyISAM的主索引和輔助索引差別不大,資料和索引是分開的,葉子結點的資料域儲存的是指向實際資料的地址
-
-
索引型別:普通索引、唯一索引(值必須唯一)、主鍵索引(會為主鍵自動建立索引)、全文索引、組合索引(最左字首)
-
聯合索引最左字首原則
-
聯合索引中區分度最高的要放最左邊
-
存在等號和非等號混合判斷條件時,在建立索引時,把等號條件的列前置
-
-
不建議使用索引的情況
-
記錄數量比較少
-
索引的選擇性比較低
-
-
優化策略:使用字首索引(短索引)
-
短索引可以提高查詢速度,節省磁碟空間和IO操作,減少索引檔案的維護開銷
-
-
磁碟I/O分析:
-
索引在記憶體,O(logn)時間忽略不計
-
用二叉樹儲存,
-
用B+樹儲存,,通常InnoDB的B+樹為2~4層,一般情況下根節點常駐記憶體,因此需要1~3次磁碟IO
-
檢視
-
在基本表上建立的表,是對基本表的一種抽象和在邏輯意義上建立的新關係
-
優點:方便操作;提高安全性,只能查詢和修改能看到的資料;邏輯上的獨立性,遮蔽了真實表結構帶來的影響
-
缺點:效能下降;無法通過複雜的檢視修改表中的資料
分割槽
-
某個表資料量太大,查詢速度會變慢,因此將表的檔案分割成為許多小塊
-
這樣可以分別在多個磁碟上儲存,對某些時間相關的應用,可以按時間分割槽
分庫分表
-
垂直分表和水平分表聯合使用的方式
讀寫分離
-
讀寫分離解決的是資料庫的寫入影響了資料庫查詢效率的問題
-
讀寫分離的實現基礎是主從複製,主資料庫執行寫操作,從資料庫執行讀操作,然後主資料庫利用主從複製將自身資料的改變同步到從資料庫中
-
可以部署多個從伺服器提高讀的速度,同時提供了冗餘資料的功能,伺服器宕機可以儘快恢復
explain執行計劃
-
可以模擬優化器執行SQL查詢語句,分析select語句或表結構的效能瓶頸,得到select查詢效率低下的原因,從而進行改進
-
欄位資訊:ID、查詢型別(普通查詢/聯合查詢/子查詢)、表、索引、索引長度、訪問型別(const/ref/range)
show profiles
-
查詢最近執行的SQL語句的執行狀態,包括狀態和耗時等
通用查詢日誌分析和慢查詢日誌分析
-
慢查詢日誌:執行時間超過指定閾值的SQL語句,可能是表太大或者沒有建立索引導致的
資料庫優化
-
優化SQL語句
-
通用查詢日誌和慢查詢日誌分析定位執行效率低的SQL語句
-
explain執行計劃分析低效的SQL執行計劃
-
show profiles分析SQL執行情況
-
寫統一的SQL語句;儘量使用索引,避免做全表的搜尋;儘量使用別名;儘量避免大事務操作/儘量避免向客戶端返回大量資料
-
-
索引優化:使用短字首
-
儘量少join;儘量少排序;儘量避免select*;儘量用join代替子查詢;儘量少or;儘量避免型別轉換
-
表結構優化:字元型別;數字型別;時間型別等
儲存引擎
InnoDB
- 聚簇索引,使用B+樹作為索引結構,主索引的葉子結點即資料檔案,因此基於主鍵查詢速度非常快,輔助索引的葉子結點是主鍵,因此使用輔助索引進行查詢需要先查詢到主鍵,在基於主索引查詢,需要兩次查詢,由於輔助索引儲存的內容是主鍵,因此基於InnoDB的資料庫表的主鍵應該小一些並且最好自增
- 提供事務支援,包括事務回滾、提交和ACID特性,以及提供系統崩潰後的修復
- 預設使用行級鎖,當查詢命中索引時使用行級鎖,當查詢未命中索引時使用表級鎖,因為行級鎖並沒有鎖到物理表上,而是鎖到了索引上
- 提供MVCC的行級鎖,提高併發操作效能,它的CPU效率基本高於其它所有的基於磁碟的關係型資料庫儲存引擎,是MySQL預設的儲存引擎
- 提供外來鍵支援
- 不使用一個單獨的變數儲存表的具體行數,因為不同事物看到的表的數量是不同的
MyISAM
- 非聚簇索引,使用B+樹作為索引結構,資料檔案和葉子結點分開儲存,葉子結點儲存的是指向資料節點的指標,主索引和輔助索引沒有太大的區別
- 不支援事務
- 使用表級鎖完成併發控制
- 不提供外來鍵支援
- 用一個單獨變數儲存表的總行數,加速select*操作
適用場景
- InnoDB適用於併發要求高,寫密集和需要事務支援以及外來鍵支援的表
- MyISAM適用於讀密集且不需要事務支援的表,適用於主從分離資料庫中的從資料庫
SQL注入
SQL注入是一種將SQL程式碼新增到輸入引數中,傳遞到伺服器解析並執行的一種攻擊手法
預防SQL注入
- 嚴格檢查輸入變數的型別和格式,如對字串變數使用正則表示式進行過濾
- 過濾和轉義特殊字元
- 利用MySQL的預編譯機制,一次編譯多次執行,提高效率,保證安全性
on和where
on和where都是篩選條件,on在表連線的過程中篩選,對left join來說無論on的條件是否為真,都會返回左表中的內容,where是對錶連線之後得到的臨時表進行篩選
group by和having
group by是分組,having是按照分組後的結果進行統計和過濾
char和varchar
char長度固定,存取速度更快,varchar長度可變,節省空間,但是存取速度更慢一些
SQL語句
select* from items where DATE_SUB(CURDATE(), INTERVAL 30 DAY) <= date(createtime)